Merge branch '3.9' into 3

This commit is contained in:
Steve Boyd 2022-04-20 11:03:27 +12:00
parent fad7c0421c
commit 8123a2d4ba
36 changed files with 6893 additions and 2 deletions

View File

@ -24,7 +24,6 @@
"php": "^7.4 || ^8.0",
"silverstripe/framework": "^4.10",
"monolog/monolog": "~1.15",
"ptcinc/solr-php-client": "^1.0",
"symfony/process": "^3.4 || ^4",
"tractorcow/silverstripe-proxy-db": "~0.1",
"ext-curl": "*"
@ -38,7 +37,10 @@
"psr-4": {
"SilverStripe\\FullTextSearch\\": "src/",
"SilverStripe\\FullTextSearch\\Tests\\": "tests/"
}
},
"classmap": [
"thirdparty/solr-php-client"
]
},
"bin": [
"bin/fulltextsearch_quickstart"

View File

@ -5,6 +5,7 @@ namespace SilverStripe\FullTextSearch\Search\Processors;
use SilverStripe\FullTextSearch\Search\Services\SearchableService;
use SilverStripe\FullTextSearch\Search\Variants\SearchVariantVersioned;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DB;
use SilverStripe\FullTextSearch\Search\Variants\SearchVariant;
use SilverStripe\FullTextSearch\Search\FullTextSearch;
use SilverStripe\Versioned\Versioned;
@ -154,6 +155,9 @@ abstract class SearchUpdateProcessor
*/
public function process()
{
if (!DB::is_active()) {
return false;
}
// Generate and commit all instances
$indexes = $this->prepareIndexes();
foreach ($indexes as $index) {

0
thirdparty/_manifest_exclude vendored Normal file
View File

View File

@ -0,0 +1,367 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Donovan Jimenez
*/
/**
* Holds Key / Value pairs that represent a Solr Document along with any associated boost
* values. Field values can be accessed by direct dereferencing such as:
* <code>
* ...
* $document->title = 'Something';
* echo $document->title;
* ...
* </code>
*
* Additionally, the field values can be iterated with foreach
*
* <code>
* foreach ($document as $fieldName => $fieldValue)
* {
* ...
* }
* </code>
*/
class Apache_Solr_Document implements IteratorAggregate
{
/**
* SVN Revision meta data for this class
*/
const SVN_REVISION = '$Revision$';
/**
* SVN ID meta data for this class
*/
const SVN_ID = '$Id$';
/**
* Document boost value
*
* @var float
*/
protected $_documentBoost = false;
/**
* Document field values, indexed by name
*
* @var array
*/
protected $_fields = array();
/**
* Document field boost values, indexed by name
*
* @var array array of floats
*/
protected $_fieldBoosts = array();
/**
* Clear all boosts and fields from this document
*/
public function clear()
{
$this->_documentBoost = false;
$this->_fields = array();
$this->_fieldBoosts = array();
}
/**
* Get current document boost
*
* @return mixed will be false for default, or else a float
*/
public function getBoost()
{
return $this->_documentBoost;
}
/**
* Set document boost factor
*
* @param mixed $boost Use false for default boost, else cast to float that should be > 0 or will be treated as false
*/
public function setBoost($boost)
{
$boost = (float) $boost;
if ($boost > 0.0)
{
$this->_documentBoost = $boost;
}
else
{
$this->_documentBoost = false;
}
}
/**
* Add a value to a multi-valued field
*
* NOTE: the solr XML format allows you to specify boosts
* PER value even though the underlying Lucene implementation
* only allows a boost per field. To remedy this, the final
* field boost value will be the product of all specified boosts
* on field values - this is similar to SolrJ's functionality.
*
* <code>
* $doc = new Apache_Solr_Document();
*
* $doc->addField('foo', 'bar', 2.0);
* $doc->addField('foo', 'baz', 3.0);
*
* // resultant field boost will be 6!
* echo $doc->getFieldBoost('foo');
* </code>
*
* @param string $key
* @param mixed $value
* @param mixed $boost Use false for default boost, else cast to float that should be > 0 or will be treated as false
*/
public function addField($key, $value, $boost = false)
{
if (!isset($this->_fields[$key]))
{
// create holding array if this is the first value
$this->_fields[$key] = array();
}
else if (!is_array($this->_fields[$key]))
{
// move existing value into array if it is not already an array
$this->_fields[$key] = array($this->_fields[$key]);
}
if ($this->getFieldBoost($key) === false)
{
// boost not already set, set it now
$this->setFieldBoost($key, $boost);
}
else if ((float) $boost > 0.0)
{
// multiply passed boost with current field boost - similar to SolrJ implementation
$this->_fieldBoosts[$key] *= (float) $boost;
}
// add value to array
$this->_fields[$key][] = $value;
}
/**
* Handle the array manipulation for a multi-valued field
*
* @param string $key
* @param string $value
* @param mixed $boost Use false for default boost, else cast to float that should be > 0 or will be treated as false
*
* @deprecated Use addField(...) instead
*/
public function setMultiValue($key, $value, $boost = false)
{
$this->addField($key, $value, $boost);
}
/**
* Get field information
*
* @param string $key
* @return mixed associative array of info if field exists, false otherwise
*/
public function getField($key)
{
if (isset($this->_fields[$key]))
{
return array(
'name' => $key,
'value' => $this->_fields[$key],
'boost' => $this->getFieldBoost($key)
);
}
return false;
}
/**
* Set a field value. Multi-valued fields should be set as arrays
* or instead use the addField(...) function which will automatically
* make sure the field is an array.
*
* @param string $key
* @param mixed $value
* @param mixed $boost Use false for default boost, else cast to float that should be > 0 or will be treated as false
*/
public function setField($key, $value, $boost = false)
{
$this->_fields[$key] = $value;
$this->setFieldBoost($key, $boost);
}
/**
* Get the currently set field boost for a document field
*
* @param string $key
* @return float currently set field boost, false if one is not set
*/
public function getFieldBoost($key)
{
return isset($this->_fieldBoosts[$key]) ? $this->_fieldBoosts[$key] : false;
}
/**
* Set the field boost for a document field
*
* @param string $key field name for the boost
* @param mixed $boost Use false for default boost, else cast to float that should be > 0 or will be treated as false
*/
public function setFieldBoost($key, $boost)
{
$boost = (float) $boost;
if ($boost > 0.0)
{
$this->_fieldBoosts[$key] = $boost;
}
else
{
$this->_fieldBoosts[$key] = false;
}
}
/**
* Return current field boosts, indexed by field name
*
* @return array
*/
public function getFieldBoosts()
{
return $this->_fieldBoosts;
}
/**
* Get the names of all fields in this document
*
* @return array
*/
public function getFieldNames()
{
return array_keys($this->_fields);
}
/**
* Get the values of all fields in this document
*
* @return array
*/
public function getFieldValues()
{
return array_values($this->_fields);
}
/**
* IteratorAggregate implementation function. Allows usage:
*
* <code>
* foreach ($document as $key => $value)
* {
* ...
* }
* </code>
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
$arrayObject = new ArrayObject($this->_fields);
return $arrayObject->getIterator();
}
/**
* Magic get for field values
*
* @param string $key
* @return mixed
*/
public function __get($key)
{
if (isset($this->_fields[$key]))
{
return $this->_fields[$key];
}
return null;
}
/**
* Magic set for field values. Multi-valued fields should be set as arrays
* or instead use the addField(...) function which will automatically
* make sure the field is an array.
*
* @param string $key
* @param mixed $value
*/
public function __set($key, $value)
{
$this->setField($key, $value);
}
/**
* Magic isset for fields values. Do not call directly. Allows usage:
*
* <code>
* isset($document->some_field);
* </code>
*
* @param string $key
* @return boolean
*/
public function __isset($key)
{
return isset($this->_fields[$key]);
}
/**
* Magic unset for field values. Do not call directly. Allows usage:
*
* <code>
* unset($document->some_field);
* </code>
*
* @param string $key
*/
public function __unset($key)
{
unset($this->_fields[$key]);
unset($this->_fieldBoosts[$key]);
}
}

View File

@ -0,0 +1,49 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Donovan Jimenez
*/
class Apache_Solr_Exception extends Exception
{
/**
* SVN Revision meta data for this class
*/
const SVN_REVISION = '$Revision$';
/**
* SVN ID meta data for this class
*/
const SVN_ID = '$Id$';
}

View File

@ -0,0 +1,88 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Timo Schmidt <timo.schmidt@aoemedia.de>, Donovan Jimenez
*/
/**
* Convenience class that implements the transport implementation. Can be extended by
* real implementations to do some of the common book keeping
*/
abstract class Apache_Solr_HttpTransport_Abstract implements Apache_Solr_HttpTransport_Interface
{
/**
* Our default timeout value for requests that don't specify a timeout
*
* @var float
*/
private $_defaultTimeout = false;
/**
* Get the current default timeout setting (initially the default_socket_timeout ini setting)
* in seconds
*
* @return float
*/
public function getDefaultTimeout()
{
// lazy load the default timeout from the ini settings
if ($this->_defaultTimeout === false)
{
$this->_defaultTimeout = (int) ini_get('default_socket_timeout');
// double check we didn't get 0 for a timeout
if ($this->_defaultTimeout <= 0)
{
$this->_defaultTimeout = 60;
}
}
return $this->_defaultTimeout;
}
/**
* Set the current default timeout for all HTTP requests
*
* @param float $timeout
*/
public function setDefaultTimeout($timeout)
{
$timeout = (float) $timeout;
if ($timeout >= 0)
{
$this->_defaultTimeout = $timeout;
}
}
}

View File

@ -0,0 +1,206 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Timo Schmidt <timo.schmidt@aoemedia.de>, Donovan Jimenez
*/
// Require Apache_Solr_HttpTransport_Abstract
require_once(dirname(__FILE__) . '/Abstract.php');
/**
* A Curl based HTTP transport. Uses a single curl session for all requests.
*/
class Apache_Solr_HttpTransport_Curl extends Apache_Solr_HttpTransport_Abstract
{
/**
* SVN Revision meta data for this class
*/
const SVN_REVISION = '$Revision:$';
/**
* SVN ID meta data for this class
*/
const SVN_ID = '$Id:$';
/**
* Curl Session Handle
*
* @var resource
*/
private $_curl;
/**
* Initializes a curl session
*/
public function __construct()
{
// initialize a CURL session
$this->_curl = curl_init();
// set common options that will not be changed during the session
curl_setopt_array($this->_curl, array(
// return the response body from curl_exec
CURLOPT_RETURNTRANSFER => true,
// get the output as binary data
CURLOPT_BINARYTRANSFER => true,
// we do not need the headers in the output, we get everything we need from curl_getinfo
CURLOPT_HEADER => false
));
}
/**
* Closes a curl session
*/
function __destruct()
{
// close our curl session
curl_close($this->_curl);
}
public function setAuthenticationCredentials($username, $password)
{
// add the options to our curl handle
curl_setopt_array($this->_curl, array(
CURLOPT_USERPWD => $username . ":" . $password,
CURLOPT_HTTPAUTH => CURLAUTH_BASIC
));
}
public function performGetRequest($url, $timeout = false)
{
// check the timeout value
if ($timeout === false || $timeout <= 0.0)
{
// use the default timeout
$timeout = $this->getDefaultTimeout();
}
// set curl GET options
curl_setopt_array($this->_curl, array(
// make sure we're returning the body
CURLOPT_NOBODY => false,
// make sure we're GET
CURLOPT_HTTPGET => true,
// set the URL
CURLOPT_URL => $url,
// set the timeout
CURLOPT_TIMEOUT => $timeout
));
// make the request
$responseBody = curl_exec($this->_curl);
// get info from the transfer
$statusCode = curl_getinfo($this->_curl, CURLINFO_HTTP_CODE);
$contentType = curl_getinfo($this->_curl, CURLINFO_CONTENT_TYPE);
return new Apache_Solr_HttpTransport_Response($statusCode, $contentType, $responseBody);
}
public function performHeadRequest($url, $timeout = false)
{
// check the timeout value
if ($timeout === false || $timeout <= 0.0)
{
// use the default timeout
$timeout = $this->getDefaultTimeout();
}
// set curl HEAD options
curl_setopt_array($this->_curl, array(
// this both sets the method to HEAD and says not to return a body
CURLOPT_NOBODY => true,
// set the URL
CURLOPT_URL => $url,
// set the timeout
CURLOPT_TIMEOUT => $timeout
));
// make the request
$responseBody = curl_exec($this->_curl);
// get info from the transfer
$statusCode = curl_getinfo($this->_curl, CURLINFO_HTTP_CODE);
$contentType = curl_getinfo($this->_curl, CURLINFO_CONTENT_TYPE);
return new Apache_Solr_HttpTransport_Response($statusCode, $contentType, $responseBody);
}
public function performPostRequest($url, $postData, $contentType, $timeout = false)
{
// check the timeout value
if ($timeout === false || $timeout <= 0.0)
{
// use the default timeout
$timeout = $this->getDefaultTimeout();
}
// set curl POST options
curl_setopt_array($this->_curl, array(
// make sure we're returning the body
CURLOPT_NOBODY => false,
// make sure we're POST
CURLOPT_POST => true,
// set the URL
CURLOPT_URL => $url,
// set the post data
CURLOPT_POSTFIELDS => $postData,
// set the content type
CURLOPT_HTTPHEADER => array("Content-Type: {$contentType}"),
// set the timeout
CURLOPT_TIMEOUT => $timeout
));
// make the request
$responseBody = curl_exec($this->_curl);
// get info from the transfer
$statusCode = curl_getinfo($this->_curl, CURLINFO_HTTP_CODE);
$contentType = curl_getinfo($this->_curl, CURLINFO_CONTENT_TYPE);
return new Apache_Solr_HttpTransport_Response($statusCode, $contentType, $responseBody);
}
}

View File

@ -0,0 +1,230 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Timo Schmidt <timo.schmidt@aoemedia.de>, Donovan Jimenez
*/
// Require Apache_Solr_HttpTransport_Abstract
require_once(dirname(__FILE__) . '/Abstract.php');
/**
* An alternative Curl HTTP transport that opens and closes a curl session for
* every request. This isn't the recommended way to use curl, but some version of
* PHP have memory issues.
*/
class Apache_Solr_HttpTransport_CurlNoReuse extends Apache_Solr_HttpTransport_Abstract
{
/**
* SVN Revision meta data for this class
*/
const SVN_REVISION = '$Revision:$';
/**
* SVN ID meta data for this class
*/
const SVN_ID = '$Id:$';
private $_authString = false;
public function setAuthenticationCredentials($username, $password)
{
// this is how curl wants it for the CURLOPT_USERPWD
$this->_authString = $username . ":" . $password;
}
public function performGetRequest($url, $timeout = false)
{
// check the timeout value
if ($timeout === false || $timeout <= 0.0)
{
// use the default timeout
$timeout = $this->getDefaultTimeout();
}
$curl = curl_init();
// set curl GET options
curl_setopt_array($curl, array(
// return the response body from curl_exec
CURLOPT_RETURNTRANSFER => true,
// get the output as binary data
CURLOPT_BINARYTRANSFER => true,
// we do not need the headers in the output, we get everything we need from curl_getinfo
CURLOPT_HEADER => false,
// set the URL
CURLOPT_URL => $url,
// set the timeout
CURLOPT_TIMEOUT => $timeout
));
// set auth if appropriate
if ($this->_authString !== false)
{
curl_setopt_array($curl, array(
CURLOPT_USERPWD => $this->_authString,
CURLOPT_HTTPAUTH => CURLAUTH_BASIC
));
}
// make the request
$responseBody = curl_exec($curl);
// get info from the transfer
$statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
$contentType = curl_getinfo($curl, CURLINFO_CONTENT_TYPE);
// close our curl session - we're done with it
curl_close($curl);
return new Apache_Solr_HttpTransport_Response($statusCode, $contentType, $responseBody);
}
public function performHeadRequest($url, $timeout = false)
{
// check the timeout value
if ($timeout === false || $timeout <= 0.0)
{
// use the default timeout
$timeout = $this->getDefaultTimeout();
}
$curl = curl_init();
// set curl HEAD options
curl_setopt_array($curl, array(
// return the response body from curl_exec
CURLOPT_RETURNTRANSFER => true,
// get the output as binary data
CURLOPT_BINARYTRANSFER => true,
// we do not need the headers in the output, we get everything we need from curl_getinfo
CURLOPT_HEADER => false,
// this both sets the method to HEAD and says not to return a body
CURLOPT_NOBODY => true,
// set the URL
CURLOPT_URL => $url,
// set the timeout
CURLOPT_TIMEOUT => $timeout
));
// set auth if appropriate
if ($this->_authString !== false)
{
curl_setopt_array($curl, array(
CURLOPT_USERPWD => $this->_authString,
CURLOPT_HTTPAUTH => CURLAUTH_BASIC
));
}
// make the request
$responseBody = curl_exec($curl);
// get info from the transfer
$statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
$contentType = curl_getinfo($curl, CURLINFO_CONTENT_TYPE);
// close our curl session - we're done with it
curl_close($curl);
return new Apache_Solr_HttpTransport_Response($statusCode, $contentType, $responseBody);
}
public function performPostRequest($url, $postData, $contentType, $timeout = false)
{
// check the timeout value
if ($timeout === false || $timeout <= 0.0)
{
// use the default timeout
$timeout = $this->getDefaultTimeout();
}
$curl = curl_init();
// set curl POST options
curl_setopt_array($curl, array(
// return the response body from curl_exec
CURLOPT_RETURNTRANSFER => true,
// get the output as binary data
CURLOPT_BINARYTRANSFER => true,
// we do not need the headers in the output, we get everything we need from curl_getinfo
CURLOPT_HEADER => false,
// make sure we're POST
CURLOPT_POST => true,
// set the URL
CURLOPT_URL => $url,
// set the post data
CURLOPT_POSTFIELDS => $postData,
// set the content type
CURLOPT_HTTPHEADER => array("Content-Type: {$contentType}"),
// set the timeout
CURLOPT_TIMEOUT => $timeout
));
// set auth if appropriate
if ($this->_authString !== false)
{
curl_setopt_array($curl, array(
CURLOPT_USERPWD => $this->_authString,
CURLOPT_HTTPAUTH => CURLAUTH_BASIC
));
}
// make the request
$responseBody = curl_exec($curl);
// get info from the transfer
$statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
$contentType = curl_getinfo($curl, CURLINFO_CONTENT_TYPE);
// close our curl session - we're done with it
curl_close($curl);
return new Apache_Solr_HttpTransport_Response($statusCode, $contentType, $responseBody);
}
}

View File

@ -0,0 +1,238 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Donovan Jimenez
*/
// Require Apache_Solr_HttpTransport_Abstract
require_once(dirname(__FILE__) . '/Abstract.php');
/**
* HTTP Transport implemenation that uses the builtin http URL wrappers and file_get_contents
*/
class Apache_Solr_HttpTransport_FileGetContents extends Apache_Solr_HttpTransport_Abstract
{
/**
* SVN Revision meta data for this class
*/
const SVN_REVISION = '$Revision: $';
/**
* SVN ID meta data for this class
*/
const SVN_ID = '$Id: $';
/**
* Reusable stream context resources for GET and POST operations
*
* @var resource
*/
private $_getContext, $_headContext, $_postContext;
/**
* For POST operations, we're already using the Header context value for
* specifying the content type too, so we have to keep our computed
* authorization header around
*
* @var string
*/
private $_authHeader = "";
/**
* Initializes our reuseable get and post stream contexts
*/
public function __construct()
{
$this->_getContext = stream_context_create();
$this->_headContext = stream_context_create();
$this->_postContext = stream_context_create();
}
public function setAuthenticationCredentials($username, $password)
{
// compute the Authorization header
$this->_authHeader = "Authorization: Basic " . base64_encode($username . ":" . $password);
// set it now for get and head contexts
stream_context_set_option($this->_getContext, 'http', 'header', $this->_authHeader);
stream_context_set_option($this->_headContext, 'http', 'header', $this->_authHeader);
// for post, it'll be set each time, so add an \r\n so it can be concatenated
// with the Content-Type
$this->_authHeader .= "\r\n";
}
public function performGetRequest($url, $timeout = false)
{
// set the timeout if specified
if ($timeout !== FALSE && $timeout > 0.0)
{
// timeouts with file_get_contents seem to need
// to be halved to work as expected
$timeout = (float) $timeout / 2;
stream_context_set_option($this->_getContext, 'http', 'timeout', $timeout);
}
else
{
// use the default timeout pulled from default_socket_timeout otherwise
stream_context_set_option($this->_getContext, 'http', 'timeout', $this->getDefaultTimeout());
}
// $http_response_headers will be updated by the call to file_get_contents later
// see http://us.php.net/manual/en/wrappers.http.php for documentation
// Unfortunately, it will still create a notice in analyzers if we don't set it here
$http_response_header = null;
$responseBody = @file_get_contents($url, false, $this->_getContext);
return $this->_getResponseFromParts($responseBody, $http_response_header);
}
public function performHeadRequest($url, $timeout = false)
{
stream_context_set_option($this->_headContext, array(
'http' => array(
// set HTTP method
'method' => 'HEAD',
// default timeout
'timeout' => $this->getDefaultTimeout()
)
)
);
// set the timeout if specified
if ($timeout !== FALSE && $timeout > 0.0)
{
// timeouts with file_get_contents seem to need
// to be halved to work as expected
$timeout = (float) $timeout / 2;
stream_context_set_option($this->_headContext, 'http', 'timeout', $timeout);
}
// $http_response_headers will be updated by the call to file_get_contents later
// see http://us.php.net/manual/en/wrappers.http.php for documentation
// Unfortunately, it will still create a notice in analyzers if we don't set it here
$http_response_header = null;
$responseBody = @file_get_contents($url, false, $this->_headContext);
return $this->_getResponseFromParts($responseBody, $http_response_header);
}
public function performPostRequest($url, $rawPost, $contentType, $timeout = false)
{
stream_context_set_option($this->_postContext, array(
'http' => array(
// set HTTP method
'method' => 'POST',
// Add our posted content type (and auth header - see setAuthentication)
'header' => "{$this->_authHeader}Content-Type: {$contentType}",
// the posted content
'content' => $rawPost,
// default timeout
'timeout' => $this->getDefaultTimeout()
)
)
);
// set the timeout if specified
if ($timeout !== FALSE && $timeout > 0.0)
{
// timeouts with file_get_contents seem to need
// to be halved to work as expected
$timeout = (float) $timeout / 2;
stream_context_set_option($this->_postContext, 'http', 'timeout', $timeout);
}
// $http_response_header will be updated by the call to file_get_contents later
// see http://us.php.net/manual/en/wrappers.http.php for documentation
// Unfortunately, it will still create a notice in analyzers if we don't set it here
$http_response_header = null;
$responseBody = @file_get_contents($url, false, $this->_postContext);
// reset content of post context to reclaim memory
stream_context_set_option($this->_postContext, 'http', 'content', '');
return $this->_getResponseFromParts($responseBody, $http_response_header);
}
private function _getResponseFromParts($rawResponse, $httpHeaders)
{
//Assume 0, false as defaults
$status = 0;
$contentType = false;
//iterate through headers for real status, type, and encoding
if (is_array($httpHeaders) && count($httpHeaders) > 0)
{
//look at the first headers for the HTTP status code
//and message (errors are usually returned this way)
//
//HTTP 100 Continue response can also be returned before
//the REAL status header, so we need look until we find
//the last header starting with HTTP
//
//the spec: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.1
//
//Thanks to Daniel Andersson for pointing out this oversight
while (isset($httpHeaders[0]) && substr($httpHeaders[0], 0, 4) == 'HTTP')
{
// we can do a intval on status line without the "HTTP/1.X " to get the code
$status = intval(substr($httpHeaders[0], 9));
// remove this from the headers so we can check for more
array_shift($httpHeaders);
}
//Look for the Content-Type response header and determine type
//and encoding from it (if possible - such as 'Content-Type: text/plain; charset=UTF-8')
foreach ($httpHeaders as $header)
{
// look for the header that starts appropriately
if (strncasecmp($header, 'Content-Type:', 13) == 0)
{
$contentType = substr($header, 13);
break;
}
}
}
return new Apache_Solr_HttpTransport_Response($status, $contentType, $rawResponse);
}
}

View File

@ -0,0 +1,103 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Timo Schmidt <timo.schmidt@aoemedia.de>, Donovan Jimenez
*/
// require Apache_Solr_HttpTransport_Response
require_once(dirname(__FILE__) . '/Response.php');
/**
* Interface that all Transport (HTTP Requester) implementations must implement. These
* Implementations can then be plugged into the Service instance in order to user their
* the desired method for making HTTP requests
*/
interface Apache_Solr_HttpTransport_Interface
{
/**
* Get the current default timeout for all HTTP requests
*
* @return float
*/
public function getDefaultTimeout();
/**
* Set the current default timeout for all HTTP requests
*
* @param float $timeout
*/
public function setDefaultTimeout($timeout);
/**
* Set authentication credentials to pass along with the requests.
*
* These will be used to perform HTTP Basic authentication.
*
* @param string $username
* @param string $password
*/
public function setAuthenticationCredentials($username, $password);
/**
* Perform a GET HTTP operation with an optional timeout and return the response
* contents, use getLastResponseHeaders to retrieve HTTP headers
*
* @param string $url
* @param float $timeout
* @return Apache_Solr_HttpTransport_Response HTTP response
*/
public function performGetRequest($url, $timeout = false);
/**
* Perform a HEAD HTTP operation with an optional timeout and return the response
* headers - NOTE: head requests have no response body
*
* @param string $url
* @param float $timeout
* @return Apache_Solr_HttpTransport_Response HTTP response
*/
public function performHeadRequest($url, $timeout = false);
/**
* Perform a POST HTTP operation with an optional timeout and return the response
* contents, use getLastResponseHeaders to retrieve HTTP headers
*
* @param string $url
* @param string $rawPost
* @param string $contentType
* @param float $timeout
* @return Apache_Solr_HttpTransport_Response HTTP response
*/
public function performPostRequest($url, $rawPost, $contentType, $timeout = false);
}

View File

@ -0,0 +1,254 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Donovan Jimenez
*/
/**
* Represents the required pieces of an HTTP response provided by HTTP transport
* implementations and then consumed by the Apache_Solr_Response class which provides
* decoding
*/
class Apache_Solr_HttpTransport_Response
{
/**
* Status Messages indexed by Status Code
* Obtained from: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
*
* @var array
*/
static private $_defaultStatusMessages = array(
// Specific to PHP Solr Client
0 => "Communication Error",
// Informational 1XX
100 => "Continue",
101 => "Switching Protocols",
// Successful 2XX
200 => "OK",
201 => "Created",
202 => "Accepted",
203 => "Non-Authoritative Information",
204 => "No Content",
205 => "Reset Content",
206 => "Partial Content",
// Redirection 3XX
300 => "Multiple Choices",
301 => "Moved Permanently",
302 => "Found",
303 => "See Other",
304 => "Not Modified",
305 => "Use Proxy",
307 => "Temporary Redirect",
// Client Error 4XX
400 => "Bad Request",
401 => "Unauthorized",
402 => "Payment Required",
403 => "Forbidden",
404 => "Not Found",
405 => "Method Not Allowed",
406 => "Not Acceptable",
407 => "Proxy Authentication Required",
408 => "Request Timeout",
409 => "Conflict",
410 => "Gone",
411 => "Length Required",
412 => "Precondition Failed",
413 => "Request Entity Too Large",
414 => "Request-URI Too Long",
415 => "Unsupported Media Type",
416 => "Request Range Not Satisfiable",
417 => "Expectation Failed",
// Server Error 5XX
500 => "Internal Server Error",
501 => "Not Implemented",
502 => "Bad Gateway",
503 => "Service Unavailable",
504 => "Gateway Timeout",
505 => "HTTP Version Not Supported"
);
/**
* Get the HTTP status message based on status code
*
* @return string
*/
public static function getDefaultStatusMessage($statusCode)
{
$statusCode = (int) $statusCode;
if (isset(self::$_defaultStatusMessages[$statusCode]))
{
return self::$_defaultStatusMessages[$statusCode];
}
return "Unknown Status";
}
/**
* The response's HTTP status code
*
* @var integer
*/
private $_statusCode;
/**
* The response's HTTP status message
*
* @var string
*/
private $_statusMessage;
/**
* The response's mime type
*
* @var string
*/
private $_mimeType;
/**
* The response's character encoding
*
* @var string
*/
private $_encoding;
/**
* The response's data
*
* @var string
*/
private $_responseBody;
/**
* Construct a HTTP transport response
*
* @param integer $statusCode The HTTP status code
* @param string $contentType The VALUE of the Content-Type HTTP header
* @param string $responseBody The body of the HTTP response
*/
public function __construct($statusCode, $contentType, $responseBody)
{
// set the status code, make sure its an integer
$this->_statusCode = (int) $statusCode;
// lookup up status message based on code
$this->_statusMessage = self::getDefaultStatusMessage($this->_statusCode);
// set the response body, it should always be a string
$this->_responseBody = (string) $responseBody;
// parse the content type header value for mimetype and encoding
// first set default values that will remain if we can't find
// what we're looking for in the content type
$this->_mimeType = "text/plain";
$this->_encoding = "UTF-8";
if ($contentType)
{
// now break apart the header to see if there's character encoding
$contentTypeParts = explode(';', $contentType, 2);
if (isset($contentTypeParts[0]))
{
$this->_mimeType = trim($contentTypeParts[0]);
}
if (isset($contentTypeParts[1]))
{
// we have a second part, split it further
$contentTypeParts = explode('=', $contentTypeParts[1]);
if (isset($contentTypeParts[1]))
{
$this->_encoding = trim($contentTypeParts[1]);
}
}
}
}
/**
* Get the status code of the response
*
* @return integer
*/
public function getStatusCode()
{
return $this->_statusCode;
}
/**
* Get the status message of the response
*
* @return string
*/
public function getStatusMessage()
{
return $this->_statusMessage;
}
/**
* Get the mimetype of the response body
*
* @return string
*/
public function getMimeType()
{
return $this->_mimeType;
}
/**
* Get the charset encoding of the response body.
*
* @return string
*/
public function getEncoding()
{
return $this->_encoding;
}
/**
* Get the raw response body
*
* @return string
*/
public function getBody()
{
return $this->_responseBody;
}
}

View File

@ -0,0 +1,78 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Donovan Jimenez
*/
class Apache_Solr_HttpTransportException extends Apache_Solr_Exception
{
/**
* SVN Revision meta data for this class
*/
const SVN_REVISION = '$Revision$';
/**
* SVN ID meta data for this class
*/
const SVN_ID = '$Id$';
/**
* Response for which exception was generated
*
* @var Apache_Solr_Response
*/
private $_response;
/**
* HttpTransportException Constructor
*
* @param Apache_Solr_Response $response
*/
public function __construct(Apache_Solr_Response $response)
{
parent::__construct("'{$response->getHttpStatus()}' Status: {$response->getHttpStatusMessage()}", $response->getHttpStatus());
$this->_response = $response;
}
/**
* Get the response for which this exception was generated
*
* @return Apache_Solr_Response
*/
public function getResponse()
{
return $this->_response;
}
}

View File

@ -0,0 +1,49 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Donovan Jimenez
*/
class Apache_Solr_InvalidArgumentException extends Apache_Solr_Exception
{
/**
* SVN Revision meta data for this class
*/
const SVN_REVISION = '$Revision$';
/**
* SVN ID meta data for this class
*/
const SVN_ID = '$Id$';
}

View File

@ -0,0 +1,49 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Donovan Jimenez
*/
class Apache_Solr_NoServiceAvailableException extends Apache_Solr_Exception
{
/**
* SVN Revision meta data for this class
*/
const SVN_REVISION = '$Revision$';
/**
* SVN ID meta data for this class
*/
const SVN_ID = '$Id$';
}

View File

@ -0,0 +1,49 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Donovan Jimenez
*/
class Apache_Solr_ParserException extends Apache_Solr_Exception
{
/**
* SVN Revision meta data for this class
*/
const SVN_REVISION = '$Revision$';
/**
* SVN ID meta data for this class
*/
const SVN_ID = '$Id$';
}

View File

@ -0,0 +1,246 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Donovan Jimenez
*/
require_once(dirname(__FILE__) . '/ParserException.php');
/**
* Represents a Solr response. Parses the raw response into a set of stdClass objects
* and associative arrays for easy access.
*
* Currently requires json_decode which is bundled with PHP >= 5.2.0, Alternatively can be
* installed with PECL. Zend Framework also includes a purely PHP solution.
*/
class Apache_Solr_Response
{
/**
* SVN Revision meta data for this class
*/
const SVN_REVISION = '$Revision$';
/**
* SVN ID meta data for this class
*/
const SVN_ID = '$Id$';
/**
* Holds the raw response used in construction
*
* @var Apache_Solr_HttpTransport_Response HTTP response
*/
protected $_response;
/**
* Whether the raw response has been parsed
*
* @var boolean
*/
protected $_isParsed = false;
/**
* Parsed representation of the data
*
* @var mixed
*/
protected $_parsedData;
/**
* Data parsing flags. Determines what extra processing should be done
* after the data is initially converted to a data structure.
*
* @var boolean
*/
protected $_createDocuments = true,
$_collapseSingleValueArrays = true;
/**
* Constructor. Takes the raw HTTP response body and the exploded HTTP headers
*
* @return Apache_Solr_HttpTransport_Response HTTP response
* @param boolean $createDocuments Whether to convert the documents json_decoded as stdClass instances to Apache_Solr_Document instances
* @param boolean $collapseSingleValueArrays Whether to make multivalued fields appear as single values
*/
public function __construct(Apache_Solr_HttpTransport_Response $response, $createDocuments = true, $collapseSingleValueArrays = true)
{
$this->_response = $response;
$this->_createDocuments = (bool) $createDocuments;
$this->_collapseSingleValueArrays = (bool) $collapseSingleValueArrays;
}
/**
* Get the HTTP status code
*
* @return integer
*/
public function getHttpStatus()
{
return $this->_response->getStatusCode();
}
/**
* Get the HTTP status message of the response
*
* @return string
*/
public function getHttpStatusMessage()
{
return $this->_response->getStatusMessage();
}
/**
* Get content type of this Solr response
*
* @return string
*/
public function getType()
{
return $this->_response->getMimeType();
}
/**
* Get character encoding of this response. Should usually be utf-8, but just in case
*
* @return string
*/
public function getEncoding()
{
return $this->_response->getEncoding();
}
/**
* Get the raw response as it was given to this object
*
* @return string
*/
public function getRawResponse()
{
return $this->_response->getBody();
}
/**
* Magic get to expose the parsed data and to lazily load it
*
* @param string $key
* @return mixed
*/
public function __get($key)
{
if (!$this->_isParsed)
{
$this->_parseData();
$this->_isParsed = true;
}
if (isset($this->_parsedData->$key))
{
return $this->_parsedData->$key;
}
return null;
}
/**
* Magic function for isset function on parsed data
*
* @param string $key
* @return boolean
*/
public function __isset($key)
{
if (!$this->_isParsed)
{
$this->_parseData();
$this->_isParsed = true;
}
return isset($this->_parsedData->$key);
}
/**
* Parse the raw response into the parsed_data array for access
*
* @throws Apache_Solr_ParserException If the data could not be parsed
*/
protected function _parseData()
{
//An alternative would be to use Zend_Json::decode(...)
$data = json_decode($this->_response->getBody());
// check that we receive a valid JSON response - we should never receive a null
if ($data === null)
{
throw new Apache_Solr_ParserException('Solr response does not appear to be valid JSON, please examine the raw response with getRawResponse() method');
}
//if we're configured to collapse single valued arrays or to convert them to Apache_Solr_Document objects
//and we have response documents, then try to collapse the values and / or convert them now
if (($this->_createDocuments || $this->_collapseSingleValueArrays) && isset($data->response) && is_array($data->response->docs))
{
$documents = array();
foreach ($data->response->docs as $originalDocument)
{
if ($this->_createDocuments)
{
$document = new Apache_Solr_Document();
}
else
{
$document = $originalDocument;
}
foreach ($originalDocument as $key => $value)
{
//If a result is an array with only a single
//value then its nice to be able to access
//it as if it were always a single value
if ($this->_collapseSingleValueArrays && is_array($value) && count($value) <= 1)
{
$value = array_shift($value);
}
$document->$key = $value;
}
$documents[] = $document;
}
$data->response->docs = $documents;
}
$this->_parsedData = $data;
}
}

View File

@ -0,0 +1,1211 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Donovan Jimenez
*/
// See Issue #1 (http://code.google.com/p/solr-php-client/issues/detail?id=1)
// Doesn't follow typical include path conventions, but is more convenient for users
require_once(dirname(__FILE__) . '/Exception.php');
require_once(dirname(__FILE__) . '/HttpTransportException.php');
require_once(dirname(__FILE__) . '/InvalidArgumentException.php');
require_once(dirname(__FILE__) . '/Document.php');
require_once(dirname(__FILE__) . '/Response.php');
require_once(dirname(__FILE__) . '/HttpTransport/Interface.php');
/**
* Starting point for the Solr API. Represents a Solr server resource and has
* methods for pinging, adding, deleting, committing, optimizing and searching.
*
* Example Usage (see also http://code.google.com/p/solr-php-client/wiki/ExampleUsage):
* <code>
* ...
* $solr = new Apache_Solr_Service(); //or explicitly new Apache_Solr_Service('localhost', 8180, '/solr')
*
* $solr->deleteByQuery('*:*'); //deletes ALL documents - be careful :)
*
* $document = new Apache_Solr_Document();
* $document->id = uniqid(); //or something else suitably unique
*
* $document->title = 'Some Title';
* $document->content = 'Some content for this wonderful document. Blah blah blah.';
*
* $solr->addDocument($document); //if you're going to be adding documents in bulk using addDocuments
* //with an array of documents is faster
*
* $solr->commit(); //commit to see the deletes and the document
* $solr->optimize(); //merges multiple segments into one
*
* //and the one we all care about, search!
* //any other common or custom parameters to the request handler can go in the
* //optional 4th array argument.
* $solr->search('content:blah', 0, 10, array('sort' => 'timestamp desc'));
* ...
* </code>
*/
class Apache_Solr_Service
{
/**
* SVN Revision meta data for this class
*/
const SVN_REVISION = '$Revision$';
/**
* SVN ID meta data for this class
*/
const SVN_ID = '$Id$';
/**
* SVN HeadURL meta data for this class
*/
const SVN_URL = '$HeadURL$';
/**
* Response writer we'll request - JSON. See http://code.google.com/p/solr-php-client/issues/detail?id=6#c1 for reasoning
*/
const SOLR_WRITER = 'json';
/**
* NamedList Treatment constants
*/
const NAMED_LIST_FLAT = 'flat';
const NAMED_LIST_MAP = 'map';
/**
* Search HTTP Methods
*/
const METHOD_GET = 'GET';
const METHOD_POST = 'POST';
/**
* Servlet mappings
*/
const PING_SERVLET = 'admin/ping';
const UPDATE_SERVLET = 'update';
const SEARCH_SERVLET = 'select';
const SYSTEM_SERVLET = 'admin/system';
const THREADS_SERVLET = 'admin/threads';
const EXTRACT_SERVLET = 'update/extract';
/**
* Server identification strings
*
* @var string
*/
protected $_host, $_port, $_path;
/**
* Whether {@link Apache_Solr_Response} objects should create {@link Apache_Solr_Document}s in
* the returned parsed data
*
* @var boolean
*/
protected $_createDocuments = true;
/**
* Whether {@link Apache_Solr_Response} objects should have multivalue fields with only a single value
* collapsed to appear as a single value would.
*
* @var boolean
*/
protected $_collapseSingleValueArrays = true;
/**
* How NamedLists should be formatted in the output. This specifically effects facet counts. Valid values
* are {@link Apache_Solr_Service::NAMED_LIST_MAP} (default) or {@link Apache_Solr_Service::NAMED_LIST_FLAT}.
*
* @var string
*/
protected $_namedListTreatment = self::NAMED_LIST_MAP;
/**
* Query delimiters. Someone might want to be able to change
* these (to use &amp; instead of & for example), so I've provided them.
*
* @var string
*/
protected $_queryDelimiter = '?', $_queryStringDelimiter = '&', $_queryBracketsEscaped = true;
/**
* Constructed servlet full path URLs
*
* @var string
*/
protected $_pingUrl, $_updateUrl, $_searchUrl, $_systemUrl, $_threadsUrl;
/**
* Keep track of whether our URLs have been constructed
*
* @var boolean
*/
protected $_urlsInited = false;
/**
* HTTP Transport implementation (pluggable)
*
* @var Apache_Solr_HttpTransport_Interface
*/
protected $_httpTransport = false;
/**
* Escape a value for special query characters such as ':', '(', ')', '*', '?', etc.
*
* NOTE: inside a phrase fewer characters need escaped, use {@link Apache_Solr_Service::escapePhrase()} instead
*
* @param string $value
* @return string
*/
static public function escape($value)
{
//list taken from http://lucene.apache.org/java/docs/queryparsersyntax.html#Escaping%20Special%20Characters
$pattern = '/(\+|-|&&|\|\||!|\(|\)|\{|}|\[|]|\^|"|~|\*|\?|:|\\\)/';
$replace = '\\\$1';
return preg_replace($pattern, $replace, $value);
}
/**
* Escape a value meant to be contained in a phrase for special query characters
*
* @param string $value
* @return string
*/
static public function escapePhrase($value)
{
$pattern = '/("|\\\)/';
$replace = '\\\$1';
return preg_replace($pattern, $replace, $value);
}
/**
* Convenience function for creating phrase syntax from a value
*
* @param string $value
* @return string
*/
static public function phrase($value)
{
return '"' . self::escapePhrase($value) . '"';
}
/**
* Constructor. All parameters are optional and will take on default values
* if not specified.
*
* @param string $host
* @param string $port
* @param string $path
* @param Apache_Solr_HttpTransport_Interface $httpTransport
*/
public function __construct($host = 'localhost', $port = 8180, $path = '/solr/', $httpTransport = false)
{
$this->setHost($host);
$this->setPort($port);
$this->setPath($path);
$this->_initUrls();
if ($httpTransport)
{
$this->setHttpTransport($httpTransport);
}
// check that our php version is >= 5.1.3 so we can correct for http_build_query behavior later
$this->_queryBracketsEscaped = version_compare(phpversion(), '5.1.3', '>=');
}
/**
* Return a valid http URL given this server's host, port and path and a provided servlet name
*
* @param string $servlet
* @return string
*/
protected function _constructUrl($servlet, $params = array())
{
if (count($params))
{
//escape all parameters appropriately for inclusion in the query string
$escapedParams = array();
foreach ($params as $key => $value)
{
$escapedParams[] = urlencode($key) . '=' . urlencode($value);
}
$queryString = $this->_queryDelimiter . implode($this->_queryStringDelimiter, $escapedParams);
}
else
{
$queryString = '';
}
return 'http://' . $this->_host . ':' . $this->_port . $this->_path . $servlet . $queryString;
}
/**
* Construct the Full URLs for the three servlets we reference
*/
protected function _initUrls()
{
//Initialize our full servlet URLs now that we have server information
$this->_extractUrl = $this->_constructUrl(self::EXTRACT_SERVLET);
$this->_pingUrl = $this->_constructUrl(self::PING_SERVLET);
$this->_searchUrl = $this->_constructUrl(self::SEARCH_SERVLET);
$this->_systemUrl = $this->_constructUrl(self::SYSTEM_SERVLET, array('wt' => self::SOLR_WRITER));
$this->_threadsUrl = $this->_constructUrl(self::THREADS_SERVLET, array('wt' => self::SOLR_WRITER ));
$this->_updateUrl = $this->_constructUrl(self::UPDATE_SERVLET, array('wt' => self::SOLR_WRITER ));
$this->_urlsInited = true;
}
protected function _generateQueryString($params)
{
// use http_build_query to encode our arguments because its faster
// than urlencoding all the parts ourselves in a loop
//
// because http_build_query treats arrays differently than we want to, correct the query
// string by changing foo[#]=bar (# being an actual number) parameter strings to just
// multiple foo=bar strings. This regex should always work since '=' will be urlencoded
// anywhere else the regex isn't expecting it
//
// NOTE: before php 5.1.3 brackets were not url encoded by http_build query - we've checked
// the php version in the constructor and put the results in the instance variable. Also, before
// 5.1.2 the arg_separator parameter was not available, so don't use it
if ($this->_queryBracketsEscaped)
{
$queryString = http_build_query($params, null, $this->_queryStringDelimiter);
return preg_replace('/%5B(?:[0-9]|[1-9][0-9]+)%5D=/', '=', $queryString);
}
else
{
$queryString = http_build_query($params);
return preg_replace('/\\[(?:[0-9]|[1-9][0-9]+)\\]=/', '=', $queryString);
}
}
/**
* Central method for making a get operation against this Solr Server
*
* @param string $url
* @param float $timeout Read timeout in seconds
* @return Apache_Solr_Response
*
* @throws Apache_Solr_HttpTransportException If a non 200 response status is returned
*/
protected function _sendRawGet($url, $timeout = FALSE)
{
$httpTransport = $this->getHttpTransport();
$httpResponse = $httpTransport->performGetRequest($url, $timeout);
$solrResponse = new Apache_Solr_Response($httpResponse, $this->_createDocuments, $this->_collapseSingleValueArrays);
if ($solrResponse->getHttpStatus() != 200)
{
throw new Apache_Solr_HttpTransportException($solrResponse);
}
return $solrResponse;
}
/**
* Central method for making a post operation against this Solr Server
*
* @param string $url
* @param string $rawPost
* @param float $timeout Read timeout in seconds
* @param string $contentType
* @return Apache_Solr_Response
*
* @throws Apache_Solr_HttpTransportException If a non 200 response status is returned
*/
protected function _sendRawPost($url, $rawPost, $timeout = FALSE, $contentType = 'text/xml; charset=UTF-8')
{
$httpTransport = $this->getHttpTransport();
$httpResponse = $httpTransport->performPostRequest($url, $rawPost, $contentType, $timeout);
$solrResponse = new Apache_Solr_Response($httpResponse, $this->_createDocuments, $this->_collapseSingleValueArrays);
if ($solrResponse->getHttpStatus() != 200)
{
throw new Apache_Solr_HttpTransportException($solrResponse);
}
return $solrResponse;
}
/**
* Returns the set host
*
* @return string
*/
public function getHost()
{
return $this->_host;
}
/**
* Set the host used. If empty will fallback to constants
*
* @param string $host
*
* @throws Apache_Solr_InvalidArgumentException If the host parameter is empty
*/
public function setHost($host)
{
//Use the provided host or use the default
if (empty($host))
{
throw new Apache_Solr_InvalidArgumentException('Host parameter is empty');
}
else
{
$this->_host = $host;
}
if ($this->_urlsInited)
{
$this->_initUrls();
}
}
/**
* Get the set port
*
* @return integer
*/
public function getPort()
{
return $this->_port;
}
/**
* Set the port used. If empty will fallback to constants
*
* @param integer $port
*
* @throws Apache_Solr_InvalidArgumentException If the port parameter is empty
*/
public function setPort($port)
{
//Use the provided port or use the default
$port = (int) $port;
if ($port <= 0)
{
throw new Apache_Solr_InvalidArgumentException('Port is not a valid port number');
}
else
{
$this->_port = $port;
}
if ($this->_urlsInited)
{
$this->_initUrls();
}
}
/**
* Get the set path.
*
* @return string
*/
public function getPath()
{
return $this->_path;
}
/**
* Set the path used. If empty will fallback to constants
*
* @param string $path
*/
public function setPath($path)
{
$path = trim($path, '/');
if (strlen($path) > 0)
{
$this->_path = '/' . $path . '/';
}
else
{
$this->_path = '/';
}
if ($this->_urlsInited)
{
$this->_initUrls();
}
}
/**
* Get the current configured HTTP Transport
*
* @return HttpTransportInterface
*/
public function getHttpTransport()
{
// lazy load a default if one has not be set
if ($this->_httpTransport === false)
{
require_once(dirname(__FILE__) . '/HttpTransport/FileGetContents.php');
$this->_httpTransport = new Apache_Solr_HttpTransport_FileGetContents();
}
return $this->_httpTransport;
}
/**
* Set the HTTP Transport implemenation that will be used for all HTTP requests
*
* @param Apache_Solr_HttpTransport_Interface
*/
public function setHttpTransport(Apache_Solr_HttpTransport_Interface $httpTransport)
{
$this->_httpTransport = $httpTransport;
}
/**
* Set the create documents flag. This determines whether {@link Apache_Solr_Response} objects will
* parse the response and create {@link Apache_Solr_Document} instances in place.
*
* @param boolean $createDocuments
*/
public function setCreateDocuments($createDocuments)
{
$this->_createDocuments = (bool) $createDocuments;
}
/**
* Get the current state of teh create documents flag.
*
* @return boolean
*/
public function getCreateDocuments()
{
return $this->_createDocuments;
}
/**
* Set the collapse single value arrays flag.
*
* @param boolean $collapseSingleValueArrays
*/
public function setCollapseSingleValueArrays($collapseSingleValueArrays)
{
$this->_collapseSingleValueArrays = (bool) $collapseSingleValueArrays;
}
/**
* Get the current state of the collapse single value arrays flag.
*
* @return boolean
*/
public function getCollapseSingleValueArrays()
{
return $this->_collapseSingleValueArrays;
}
/**
* Get the current default timeout setting (initially the default_socket_timeout ini setting)
* in seconds
*
* @return float
*
* @deprecated Use the getDefaultTimeout method on the HTTP transport implementation
*/
public function getDefaultTimeout()
{
return $this->getHttpTransport()->getDefaultTimeout();
}
/**
* Set the default timeout for all calls that aren't passed a specific timeout
*
* @param float $timeout Timeout value in seconds
*
* @deprecated Use the setDefaultTimeout method on the HTTP transport implementation
*/
public function setDefaultTimeout($timeout)
{
$this->getHttpTransport()->setDefaultTimeout($timeout);
}
/**
* Convenience method to set authentication credentials on the current HTTP transport implementation
*
* @param string $username
* @param string $password
*/
public function setAuthenticationCredentials($username, $password)
{
$this->getHttpTransport()->setAuthenticationCredentials($username, $password);
}
/**
* Set how NamedLists should be formatted in the response data. This mainly effects
* the facet counts format.
*
* @param string $namedListTreatment
* @throws Apache_Solr_InvalidArgumentException If invalid option is set
*/
public function setNamedListTreatment($namedListTreatment)
{
switch ((string) $namedListTreatment)
{
case Apache_Solr_Service::NAMED_LIST_FLAT:
$this->_namedListTreatment = Apache_Solr_Service::NAMED_LIST_FLAT;
break;
case Apache_Solr_Service::NAMED_LIST_MAP:
$this->_namedListTreatment = Apache_Solr_Service::NAMED_LIST_MAP;
break;
default:
throw new Apache_Solr_InvalidArgumentException('Not a valid named list treatement option');
}
}
/**
* Get the current setting for named list treatment.
*
* @return string
*/
public function getNamedListTreatment()
{
return $this->_namedListTreatment;
}
/**
* Set the string used to separate the path form the query string.
* Defaulted to '?'
*
* @param string $queryDelimiter
*/
public function setQueryDelimiter($queryDelimiter)
{
$this->_queryDelimiter = $queryDelimiter;
}
/**
* Set the string used to separate the parameters in thequery string
* Defaulted to '&'
*
* @param string $queryStringDelimiter
*/
public function setQueryStringDelimiter($queryStringDelimiter)
{
$this->_queryStringDelimiter = $queryStringDelimiter;
}
/**
* Call the /admin/ping servlet, can be used to quickly tell if a connection to the
* server is able to be made.
*
* @param float $timeout maximum time to wait for ping in seconds, -1 for unlimited (default is 2)
* @return float Actual time taken to ping the server, FALSE if timeout or HTTP error status occurs
*/
public function ping($timeout = 2)
{
$start = microtime(true);
$httpTransport = $this->getHttpTransport();
$httpResponse = $httpTransport->performHeadRequest($this->_pingUrl, $timeout);
$solrResponse = new Apache_Solr_Response($httpResponse, $this->_createDocuments, $this->_collapseSingleValueArrays);
if ($solrResponse->getHttpStatus() == 200)
{
return microtime(true) - $start;
}
else
{
return false;
}
}
/**
* Call the /admin/system servlet and retrieve system information about Solr
*
* @return Apache_Solr_Response
*
* @throws Apache_Solr_HttpTransportException If an error occurs during the service call
*/
public function system()
{
return $this->_sendRawGet($this->_systemUrl);
}
/**
* Call the /admin/threads servlet and retrieve information about all threads in the
* Solr servlet's thread group. Useful for diagnostics.
*
* @return Apache_Solr_Response
*
* @throws Apache_Solr_HttpTransportException If an error occurs during the service call
*/
public function threads()
{
return $this->_sendRawGet($this->_threadsUrl);
}
/**
* Raw Add Method. Takes a raw post body and sends it to the update service. Post body
* should be a complete and well formed "add" xml document.
*
* @param string $rawPost
* @return Apache_Solr_Response
*
* @throws Apache_Solr_HttpTransportException If an error occurs during the service call
*/
public function add($rawPost)
{
return $this->_sendRawPost($this->_updateUrl, $rawPost);
}
/**
* Add a Solr Document to the index
*
* @param Apache_Solr_Document $document
* @param boolean $allowDups
* @param boolean $overwritePending
* @param boolean $overwriteCommitted
* @param integer $commitWithin The number of milliseconds that a document must be committed within, see @{link http://wiki.apache.org/solr/UpdateXmlMessages#The_Update_Schema} for details. If left empty this property will not be set in the request.
* @return Apache_Solr_Response
*
* @throws Apache_Solr_HttpTransportException If an error occurs during the service call
*/
public function addDocument(Apache_Solr_Document $document, $allowDups = false, $overwritePending = true, $overwriteCommitted = true, $commitWithin = 0)
{
$dupValue = $allowDups ? 'true' : 'false';
$pendingValue = $overwritePending ? 'true' : 'false';
$committedValue = $overwriteCommitted ? 'true' : 'false';
$commitWithin = (int) $commitWithin;
$commitWithinString = $commitWithin > 0 ? " commitWithin=\"{$commitWithin}\"" : '';
$rawPost = "<add allowDups=\"{$dupValue}\" overwritePending=\"{$pendingValue}\" overwriteCommitted=\"{$committedValue}\"{$commitWithinString}>";
$rawPost .= $this->_documentToXmlFragment($document);
$rawPost .= '</add>';
return $this->add($rawPost);
}
/**
* Add an array of Solr Documents to the index all at once
*
* @param array $documents Should be an array of Apache_Solr_Document instances
* @param boolean $allowDups
* @param boolean $overwritePending
* @param boolean $overwriteCommitted
* @param integer $commitWithin The number of milliseconds that a document must be committed within, see @{link http://wiki.apache.org/solr/UpdateXmlMessages#The_Update_Schema} for details. If left empty this property will not be set in the request.
* @return Apache_Solr_Response
*
* @throws Apache_Solr_HttpTransportException If an error occurs during the service call
*/
public function addDocuments($documents, $allowDups = false, $overwritePending = true, $overwriteCommitted = true, $commitWithin = 0)
{
$dupValue = $allowDups ? 'true' : 'false';
$pendingValue = $overwritePending ? 'true' : 'false';
$committedValue = $overwriteCommitted ? 'true' : 'false';
$commitWithin = (int) $commitWithin;
$commitWithinString = $commitWithin > 0 ? " commitWithin=\"{$commitWithin}\"" : '';
$rawPost = "<add allowDups=\"{$dupValue}\" overwritePending=\"{$pendingValue}\" overwriteCommitted=\"{$committedValue}\"{$commitWithinString}>";
foreach ($documents as $document)
{
if ($document instanceof Apache_Solr_Document)
{
$rawPost .= $this->_documentToXmlFragment($document);
}
}
$rawPost .= '</add>';
return $this->add($rawPost);
}
/**
* Create an XML fragment from a {@link Apache_Solr_Document} instance appropriate for use inside a Solr add call
*
* @return string
*/
protected function _documentToXmlFragment(Apache_Solr_Document $document)
{
$xml = '<doc';
if ($document->getBoost() !== false)
{
$xml .= ' boost="' . $document->getBoost() . '"';
}
$xml .= '>';
foreach ($document as $key => $value)
{
$fieldBoost = $document->getFieldBoost($key);
$key = htmlspecialchars($key, ENT_QUOTES, 'UTF-8');
if (is_array($value))
{
foreach ($value as $multivalue)
{
$xml .= '<field name="' . $key . '"';
if ($fieldBoost !== false)
{
$xml .= ' boost="' . $fieldBoost . '"';
// only set the boost for the first field in the set
$fieldBoost = false;
}
$multivalue = htmlspecialchars($multivalue, ENT_NOQUOTES, 'UTF-8');
$xml .= '>' . $multivalue . '</field>';
}
}
else
{
$xml .= '<field name="' . $key . '"';
if ($fieldBoost !== false)
{
$xml .= ' boost="' . $fieldBoost . '"';
}
$value = htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8');
$xml .= '>' . $value . '</field>';
}
}
$xml .= '</doc>';
// replace any control characters to avoid Solr XML parser exception
return $this->_stripCtrlChars($xml);
}
/**
* Replace control (non-printable) characters from string that are invalid to Solr's XML parser with a space.
*
* @param string $string
* @return string
*/
protected function _stripCtrlChars($string)
{
// See: http://w3.org/International/questions/qa-forms-utf-8.html
// Printable utf-8 does not include any of these chars below x7F
return preg_replace('@[\x00-\x08\x0B\x0C\x0E-\x1F]@', ' ', $string);
}
/**
* Send a commit command. Will be synchronous unless both wait parameters are set to false.
*
* @param boolean $expungeDeletes Defaults to false, merge segments with deletes away
* @param boolean $waitFlush Defaults to true, block until index changes are flushed to disk
* @param boolean $waitSearcher Defaults to true, block until a new searcher is opened and registered as the main query searcher, making the changes visible
* @param float $timeout Maximum expected duration (in seconds) of the commit operation on the server (otherwise, will throw a communication exception). Defaults to 1 hour
* @return Apache_Solr_Response
*
* @throws Apache_Solr_HttpTransportException If an error occurs during the service call
*/
public function commit($expungeDeletes = false, $waitFlush = true, $waitSearcher = true, $timeout = 3600)
{
$expungeValue = $expungeDeletes ? 'true' : 'false';
$flushValue = $waitFlush ? 'true' : 'false';
$searcherValue = $waitSearcher ? 'true' : 'false';
$rawPost = '<commit expungeDeletes="' . $expungeValue . '" waitFlush="' . $flushValue . '" waitSearcher="' . $searcherValue . '" />';
return $this->_sendRawPost($this->_updateUrl, $rawPost, $timeout);
}
/**
* Raw Delete Method. Takes a raw post body and sends it to the update service. Body should be
* a complete and well formed "delete" xml document
*
* @param string $rawPost Expected to be utf-8 encoded xml document
* @param float $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception)
* @return Apache_Solr_Response
*
* @throws Apache_Solr_HttpTransportException If an error occurs during the service call
*/
public function delete($rawPost, $timeout = 3600)
{
return $this->_sendRawPost($this->_updateUrl, $rawPost, $timeout);
}
/**
* Create a delete document based on document ID
*
* @param string $id Expected to be utf-8 encoded
* @param boolean $fromPending
* @param boolean $fromCommitted
* @param float $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception)
* @return Apache_Solr_Response
*
* @throws Apache_Solr_HttpTransportException If an error occurs during the service call
*/
public function deleteById($id, $fromPending = true, $fromCommitted = true, $timeout = 3600)
{
$pendingValue = $fromPending ? 'true' : 'false';
$committedValue = $fromCommitted ? 'true' : 'false';
//escape special xml characters
$id = htmlspecialchars($id, ENT_NOQUOTES, 'UTF-8');
$rawPost = '<delete fromPending="' . $pendingValue . '" fromCommitted="' . $committedValue . '"><id>' . $id . '</id></delete>';
return $this->delete($rawPost, $timeout);
}
/**
* Create and post a delete document based on multiple document IDs.
*
* @param array $ids Expected to be utf-8 encoded strings
* @param boolean $fromPending
* @param boolean $fromCommitted
* @param float $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception)
* @return Apache_Solr_Response
*
* @throws Apache_Solr_HttpTransportException If an error occurs during the service call
*/
public function deleteByMultipleIds($ids, $fromPending = true, $fromCommitted = true, $timeout = 3600)
{
$pendingValue = $fromPending ? 'true' : 'false';
$committedValue = $fromCommitted ? 'true' : 'false';
$rawPost = '<delete fromPending="' . $pendingValue . '" fromCommitted="' . $committedValue . '">';
foreach ($ids as $id)
{
//escape special xml characters
$id = htmlspecialchars($id, ENT_NOQUOTES, 'UTF-8');
$rawPost .= '<id>' . $id . '</id>';
}
$rawPost .= '</delete>';
return $this->delete($rawPost, $timeout);
}
/**
* Create a delete document based on a query and submit it
*
* @param string $rawQuery Expected to be utf-8 encoded
* @param boolean $fromPending
* @param boolean $fromCommitted
* @param float $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception)
* @return Apache_Solr_Response
*
* @throws Apache_Solr_HttpTransportException If an error occurs during the service call
*/
public function deleteByQuery($rawQuery, $fromPending = true, $fromCommitted = true, $timeout = 3600)
{
$pendingValue = $fromPending ? 'true' : 'false';
$committedValue = $fromCommitted ? 'true' : 'false';
// escape special xml characters
$rawQuery = htmlspecialchars($rawQuery, ENT_NOQUOTES, 'UTF-8');
$rawPost = '<delete fromPending="' . $pendingValue . '" fromCommitted="' . $committedValue . '"><query>' . $rawQuery . '</query></delete>';
return $this->delete($rawPost, $timeout);
}
/**
* Use Solr Cell to extract document contents. See {@link http://wiki.apache.org/solr/ExtractingRequestHandler} for information on how
* to use Solr Cell and what parameters are available.
*
* NOTE: when passing an Apache_Solr_Document instance, field names and boosts will automatically be prepended by "literal." and "boost."
* as appropriate. Any keys from the $params array will NOT be treated this way. Any mappings from the document will overwrite key / value
* 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
* pass in a document isntance with an "id" field" - the document's value(s) will take precedence).
*
* @param string $file Path to file to extract data from
* @param array $params optional array of key value pairs that will be sent with the post (see Solr Cell documentation)
* @param Apache_Solr_Document $document optional document that will be used to generate post parameters (literal.* and boost.* params)
* @param string $mimetype optional mimetype specification (for the file being extracted)
*
* @return Apache_Solr_Response
*
* @throws Apache_Solr_InvalidArgumentException if $file, $params, or $document are invalid.
*/
public function extract($file, $params = array(), $document = null, $mimetype = 'application/octet-stream')
{
// check if $params is an array (allow null for default empty array)
if (!is_null($params))
{
if (!is_array($params))
{
throw new Apache_Solr_InvalidArgumentException("\$params must be a valid array or null");
}
}
else
{
$params = array();
}
// if $file is an http request, defer to extractFromUrl instead
if (substr($file, 0, 7) == 'http://' || substr($file, 0, 8) == 'https://')
{
return $this->extractFromUrl($file, $params, $document, $mimetype);
}
// read the contents of the file
$contents = @file_get_contents($file);
if ($contents !== false)
{
// add the resource.name parameter if not specified
if (!isset($params['resource.name']))
{
$params['resource.name'] = basename($file);
}
// delegate the rest to extractFromString
return $this->extractFromString($contents, $params, $document, $mimetype);
}
else
{
throw new Apache_Solr_InvalidArgumentException("File '{$file}' is empty or could not be read");
}
}
/**
* Use Solr Cell to extract document contents. See {@link http://wiki.apache.org/solr/ExtractingRequestHandler} for information on how
* to use Solr Cell and what parameters are available.
*
* NOTE: when passing an Apache_Solr_Document instance, field names and boosts will automatically be prepended by "literal." and "boost."
* as appropriate. Any keys from the $params array will NOT be treated this way. Any mappings from the document will overwrite key / value
* 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
* pass in a document isntance with an "id" field" - the document's value(s) will take precedence).
*
* @param string $data Data that will be passed to Solr Cell
* @param array $params optional array of key value pairs that will be sent with the post (see Solr Cell documentation)
* @param Apache_Solr_Document $document optional document that will be used to generate post parameters (literal.* and boost.* params)
* @param string $mimetype optional mimetype specification (for the file being extracted)
*
* @return Apache_Solr_Response
*
* @throws Apache_Solr_InvalidArgumentException if $file, $params, or $document are invalid.
*
* @todo Should be using multipart/form-data to post parameter values, but I could not get my implementation to work. Needs revisisted.
*/
public function extractFromString($data, $params = array(), $document = null, $mimetype = 'application/octet-stream')
{
// check if $params is an array (allow null for default empty array)
if (!is_null($params))
{
if (!is_array($params))
{
throw new Apache_Solr_InvalidArgumentException("\$params must be a valid array or null");
}
}
else
{
$params = array();
}
// make sure we receive our response in JSON and have proper name list treatment
$params['wt'] = self::SOLR_WRITER;
$params['json.nl'] = $this->_namedListTreatment;
// check if $document is an Apache_Solr_Document instance
if (!is_null($document) && $document instanceof Apache_Solr_Document)
{
// iterate document, adding literal.* and boost.* fields to $params as appropriate
foreach ($document as $field => $fieldValue)
{
// check if we need to add a boost.* parameters
$fieldBoost = $document->getFieldBoost($field);
if ($fieldBoost !== false)
{
$params["boost.{$field}"] = $fieldBoost;
}
// add the literal.* parameter
$params["literal.{$field}"] = $fieldValue;
}
}
// params will be sent to SOLR in the QUERY STRING
$queryString = $this->_generateQueryString($params);
// the file contents will be sent to SOLR as the POST BODY - we use application/octect-stream as default mimetype
return $this->_sendRawPost($this->_extractUrl . $this->_queryDelimiter . $queryString, $data, false, $mimetype);
}
/**
* Use Solr Cell to extract document contents. See {@link http://wiki.apache.org/solr/ExtractingRequestHandler} for information on how
* to use Solr Cell and what parameters are available.
*
* NOTE: when passing an Apache_Solr_Document instance, field names and boosts will automatically be prepended by "literal." and "boost."
* as appropriate. Any keys from the $params array will NOT be treated this way. Any mappings from the document will overwrite key / value
* 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
* pass in a document isntance with an "id" field" - the document's value(s) will take precedence).
*
* @param string $url URL
* @param array $params optional array of key value pairs that will be sent with the post (see Solr Cell documentation)
* @param Apache_Solr_Document $document optional document that will be used to generate post parameters (literal.* and boost.* params)
* @param string $mimetype optional mimetype specification (for the file being extracted)
*
* @return Apache_Solr_Response
*
* @throws Apache_Solr_InvalidArgumentException if $url, $params, or $document are invalid.
*/
public function extractFromUrl($url, $params = array(), $document = null, $mimetype = 'application/octet-stream')
{
// check if $params is an array (allow null for default empty array)
if (!is_null($params))
{
if (!is_array($params))
{
throw new Apache_Solr_InvalidArgumentException("\$params must be a valid array or null");
}
}
else
{
$params = array();
}
$httpTransport = $this->getHttpTransport();
// read the contents of the URL using our configured Http Transport and default timeout
$httpResponse = $httpTransport->performGetRequest($url);
// check that its a 200 response
if ($httpResponse->getStatusCode() == 200)
{
// add the resource.name parameter if not specified
if (!isset($params['resource.name']))
{
$params['resource.name'] = $url;
}
// delegate the rest to extractFromString
return $this->extractFromString($httpResponse->getBody(), $params, $document, $mimetype);
}
else
{
throw new Apache_Solr_InvalidArgumentException("URL '{$url}' returned non 200 response code");
}
}
/**
* Send an optimize command. Will be synchronous unless both wait parameters are set
* to false.
*
* @param boolean $waitFlush
* @param boolean $waitSearcher
* @param float $timeout Maximum expected duration of the commit operation on the server (otherwise, will throw a communication exception)
* @return Apache_Solr_Response
*
* @throws Apache_Solr_HttpTransportException If an error occurs during the service call
*/
public function optimize($waitFlush = true, $waitSearcher = true, $timeout = 3600)
{
$flushValue = $waitFlush ? 'true' : 'false';
$searcherValue = $waitSearcher ? 'true' : 'false';
$rawPost = '<optimize waitFlush="' . $flushValue . '" waitSearcher="' . $searcherValue . '" />';
return $this->_sendRawPost($this->_updateUrl, $rawPost, $timeout);
}
/**
* Simple Search interface
*
* @param string $query The raw query string
* @param int $offset The starting offset for result documents
* @param int $limit The maximum number of result documents to return
* @param array $params key / value pairs for other query parameters (see Solr documentation), use arrays for parameter keys used more than once (e.g. facet.field)
* @param string $method The HTTP method (Apache_Solr_Service::METHOD_GET or Apache_Solr_Service::METHOD::POST)
* @return Apache_Solr_Response
*
* @throws Apache_Solr_HttpTransportException If an error occurs during the service call
* @throws Apache_Solr_InvalidArgumentException If an invalid HTTP method is used
*/
public function search($query, $offset = 0, $limit = 10, $params = array(), $method = self::METHOD_GET)
{
// ensure params is an array
if (!is_null($params))
{
if (!is_array($params))
{
// params was specified but was not an array - invalid
throw new Apache_Solr_InvalidArgumentException("\$params must be a valid array or null");
}
}
else
{
$params = array();
}
// construct our full parameters
// common parameters in this interface
$params['wt'] = self::SOLR_WRITER;
$params['json.nl'] = $this->_namedListTreatment;
$params['q'] = $query;
$params['start'] = $offset;
$params['rows'] = $limit;
$queryString = $this->_generateQueryString($params);
if ($method == self::METHOD_GET)
{
return $this->_sendRawGet($this->_searchUrl . $this->_queryDelimiter . $queryString);
}
else if ($method == self::METHOD_POST)
{
return $this->_sendRawPost($this->_searchUrl, $queryString, FALSE, 'application/x-www-form-urlencoded; charset=UTF-8');
}
else
{
throw new Apache_Solr_InvalidArgumentException("Unsupported method '$method', please use the Apache_Solr_Service::METHOD_* constants");
}
}
}

View File

@ -0,0 +1,917 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Donovan Jimenez, Dan Wolfe
*/
// See Issue #1 (http://code.google.com/p/solr-php-client/issues/detail?id=1)
// Doesn't follow typical include path conventions, but is more convenient for users
require_once(dirname(dirname(__FILE__)) . '/Service.php');
require_once(dirname(dirname(__FILE__)) . '/NoServiceAvailableException.php');
/**
* Reference Implementation for using multiple Solr services in a distribution. Functionality
* includes:
* routing of read / write operations
* failover (on selection) for multiple read servers
*/
class Apache_Solr_Service_Balancer
{
/**
* SVN Revision meta data for this class
*/
const SVN_REVISION = '$Revision$';
/**
* SVN ID meta data for this class
*/
const SVN_ID = '$Id$';
/**
* SVN HeadURL meta data for this class
*/
const SVN_URL = '$HeadURL$';
protected $_createDocuments = true;
protected $_readableServices = array();
protected $_writeableServices = array();
protected $_currentReadService = null;
protected $_currentWriteService = null;
protected $_readPingTimeout = 2;
protected $_writePingTimeout = 4;
// Configuration for server selection backoff intervals
protected $_useBackoff = false; // Set to true to use more resillient write server selection
protected $_backoffLimit = 600; // 10 minute default maximum
protected $_backoffEscalation = 2.0; // Rate at which to increase backoff period
protected $_defaultBackoff = 2.0; // Default backoff interval
/**
* Escape a value for special query characters such as ':', '(', ')', '*', '?', etc.
*
* NOTE: inside a phrase fewer characters need escaped, use {@link Apache_Solr_Service::escapePhrase()} instead
*
* @param string $value
* @return string
*/
static public function escape($value)
{
return Apache_Solr_Service::escape($value);
}
/**
* Escape a value meant to be contained in a phrase for special query characters
*
* @param string $value
* @return string
*/
static public function escapePhrase($value)
{
return Apache_Solr_Service::escapePhrase($value);
}
/**
* Convenience function for creating phrase syntax from a value
*
* @param string $value
* @return string
*/
static public function phrase($value)
{
return Apache_Solr_Service::phrase($value);
}
/**
* Constructor. Takes arrays of read and write service instances or descriptions
*
* @param array $readableServices
* @param array $writeableServices
*/
public function __construct($readableServices = array(), $writeableServices = array())
{
//setup readable services
foreach ($readableServices as $service)
{
$this->addReadService($service);
}
//setup writeable services
foreach ($writeableServices as $service)
{
$this->addWriteService($service);
}
}
public function setReadPingTimeout($timeout)
{
$this->_readPingTimeout = $timeout;
}
public function setWritePingTimeout($timeout)
{
$this->_writePingTimeout = $timeout;
}
public function setUseBackoff($enable)
{
$this->_useBackoff = $enable;
}
/**
* Generates a service ID
*
* @param string $host
* @param integer $port
* @param string $path
* @return string
*/
protected function _getServiceId($host, $port, $path)
{
return $host . ':' . $port . $path;
}
/**
* Adds a service instance or service descriptor (if it is already
* not added)
*
* @param mixed $service
*
* @throws Apache_Solr_InvalidArgumentException If service descriptor is not valid
*/
public function addReadService($service)
{
if ($service instanceof Apache_Solr_Service)
{
$id = $this->_getServiceId($service->getHost(), $service->getPort(), $service->getPath());
$this->_readableServices[$id] = $service;
}
else if (is_array($service))
{
if (isset($service['host']) && isset($service['port']) && isset($service['path']))
{
$id = $this->_getServiceId((string)$service['host'], (int)$service['port'], (string)$service['path']);
$this->_readableServices[$id] = $service;
}
else
{
throw new Apache_Solr_InvalidArgumentException('A Readable Service description array does not have all required elements of host, port, and path');
}
}
}
/**
* Removes a service instance or descriptor from the available services
*
* @param mixed $service
*
* @throws Apache_Solr_InvalidArgumentException If service descriptor is not valid
*/
public function removeReadService($service)
{
$id = '';
if ($service instanceof Apache_Solr_Service)
{
$id = $this->_getServiceId($service->getHost(), $service->getPort(), $service->getPath());
}
else if (is_array($service))
{
if (isset($service['host']) && isset($service['port']) && isset($service['path']))
{
$id = $this->_getServiceId((string)$service['host'], (int)$service['port'], (string)$service['path']);
}
else
{
throw new Apache_Solr_InvalidArgumentException('A Readable Service description array does not have all required elements of host, port, and path');
}
}
else if (is_string($service))
{
$id = $service;
}
if ($id && isset($this->_readableServices[$id]))
{
unset($this->_readableServices[$id]);
}
}
/**
* Adds a service instance or service descriptor (if it is already
* not added)
*
* @param mixed $service
*
* @throws Apache_Solr_InvalidArgumentException If service descriptor is not valid
*/
public function addWriteService($service)
{
if ($service instanceof Apache_Solr_Service)
{
$id = $this->_getServiceId($service->getHost(), $service->getPort(), $service->getPath());
$this->_writeableServices[$id] = $service;
}
else if (is_array($service))
{
if (isset($service['host']) && isset($service['port']) && isset($service['path']))
{
$id = $this->_getServiceId((string)$service['host'], (int)$service['port'], (string)$service['path']);
$this->_writeableServices[$id] = $service;
}
else
{
throw new Apache_Solr_InvalidArgumentException('A Writeable Service description array does not have all required elements of host, port, and path');
}
}
}
/**
* Removes a service instance or descriptor from the available services
*
* @param mixed $service
*
* @throws Apache_Solr_InvalidArgumentException If service descriptor is not valid
*/
public function removeWriteService($service)
{
$id = '';
if ($service instanceof Apache_Solr_Service)
{
$id = $this->_getServiceId($service->getHost(), $service->getPort(), $service->getPath());
}
else if (is_array($service))
{
if (isset($service['host']) && isset($service['port']) && isset($service['path']))
{
$id = $this->_getServiceId((string)$service['host'], (int)$service['port'], (string)$service['path']);
}
else
{
throw new Apache_Solr_InvalidArgumentException('A Readable Service description array does not have all required elements of host, port, and path');
}
}
else if (is_string($service))
{
$id = $service;
}
if ($id && isset($this->_writeableServices[$id]))
{
unset($this->_writeableServices[$id]);
}
}
/**
* Iterate through available read services and select the first with a ping
* that satisfies configured timeout restrictions (or the default)
*
* @return Apache_Solr_Service
*
* @throws Apache_Solr_NoServiceAvailableException If there are no read services that meet requirements
*/
protected function _selectReadService($forceSelect = false)
{
if (!$this->_currentReadService || !isset($this->_readableServices[$this->_currentReadService]) || $forceSelect)
{
if ($this->_currentReadService && isset($this->_readableServices[$this->_currentReadService]) && $forceSelect)
{
// we probably had a communication error, ping the current read service, remove it if it times out
if ($this->_readableServices[$this->_currentReadService]->ping($this->_readPingTimeout) === false)
{
$this->removeReadService($this->_currentReadService);
}
}
if (count($this->_readableServices))
{
// select one of the read services at random
$ids = array_keys($this->_readableServices);
$id = $ids[rand(0, count($ids) - 1)];
$service = $this->_readableServices[$id];
if (is_array($service))
{
//convert the array definition to a client object
$service = new Apache_Solr_Service($service['host'], $service['port'], $service['path']);
$this->_readableServices[$id] = $service;
}
$service->setCreateDocuments($this->_createDocuments);
$this->_currentReadService = $id;
}
else
{
throw new Apache_Solr_NoServiceAvailableException('No read services were available');
}
}
return $this->_readableServices[$this->_currentReadService];
}
/**
* Iterate through available write services and select the first with a ping
* that satisfies configured timeout restrictions (or the default)
*
* @return Apache_Solr_Service
*
* @throws Apache_Solr_NoServiceAvailableException If there are no write services that meet requirements
*/
protected function _selectWriteService($forceSelect = false)
{
if($this->_useBackoff)
{
return $this->_selectWriteServiceSafe($forceSelect);
}
if (!$this->_currentWriteService || !isset($this->_writeableServices[$this->_currentWriteService]) || $forceSelect)
{
if ($this->_currentWriteService && isset($this->_writeableServices[$this->_currentWriteService]) && $forceSelect)
{
// we probably had a communication error, ping the current read service, remove it if it times out
if ($this->_writeableServices[$this->_currentWriteService]->ping($this->_writePingTimeout) === false)
{
$this->removeWriteService($this->_currentWriteService);
}
}
if (count($this->_writeableServices))
{
// select one of the read services at random
$ids = array_keys($this->_writeableServices);
$id = $ids[rand(0, count($ids) - 1)];
$service = $this->_writeableServices[$id];
if (is_array($service))
{
//convert the array definition to a client object
$service = new Apache_Solr_Service($service['host'], $service['port'], $service['path']);
$this->_writeableServices[$id] = $service;
}
$this->_currentWriteService = $id;
}
else
{
throw new Apache_Solr_NoServiceAvailableException('No write services were available');
}
}
return $this->_writeableServices[$this->_currentWriteService];
}
/**
* Iterate through available write services and select the first with a ping
* that satisfies configured timeout restrictions (or the default). The
* timeout period will increase until a connection is made or the limit is
* reached. This will allow for increased reliability with heavily loaded
* server(s).
*
* @return Apache_Solr_Service
*
* @throws Apache_Solr_NoServiceAvailableException If there are no write services that meet requirements
*/
protected function _selectWriteServiceSafe($forceSelect = false)
{
if (!$this->_currentWriteService || !isset($this->_writeableServices[$this->_currentWriteService]) || $forceSelect)
{
if (count($this->_writeableServices))
{
$backoff = $this->_defaultBackoff;
do {
// select one of the read services at random
$ids = array_keys($this->_writeableServices);
$id = $ids[rand(0, count($ids) - 1)];
$service = $this->_writeableServices[$id];
if (is_array($service))
{
//convert the array definition to a client object
$service = new Apache_Solr_Service($service['host'], $service['port'], $service['path']);
$this->_writeableServices[$id] = $service;
}
$this->_currentWriteService = $id;
$backoff *= $this->_backoffEscalation;
if($backoff > $this->_backoffLimit)
{
throw new Apache_Solr_NoServiceAvailableException('No write services were available. All timeouts exceeded.');
}
} while($this->_writeableServices[$this->_currentWriteService]->ping($backoff) === false);
}
else
{
throw new Apache_Solr_NoServiceAvailableException('No write services were available');
}
}
return $this->_writeableServices[$this->_currentWriteService];
}
/**
* Set the create documents flag. This determines whether {@link Apache_Solr_Response} objects will
* parse the response and create {@link Apache_Solr_Document} instances in place.
*
* @param boolean $createDocuments
*/
public function setCreateDocuments($createDocuments)
{
$this->_createDocuments = (bool) $createDocuments;
// set on current read service
if ($this->_currentReadService)
{
$service = $this->_selectReadService();
$service->setCreateDocuments($createDocuments);
}
}
/**
* Get the current state of teh create documents flag.
*
* @return boolean
*/
public function getCreateDocuments()
{
return $this->_createDocuments;
}
/**
* Raw Add Method. Takes a raw post body and sends it to the update service. Post body
* should be a complete and well formed "add" xml document.
*
* @param string $rawPost
* @return Apache_Solr_Response
*
* @throws Apache_Solr_HttpTransportException If an error occurs during the service call
*/
public function add($rawPost)
{
$service = $this->_selectWriteService();
do
{
try
{
return $service->add($rawPost);
}
catch (Apache_Solr_HttpTransportException $e)
{
if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR
{
throw $e;
}
}
$service = $this->_selectWriteService(true);
} while ($service);
return false;
}
/**
* Add a Solr Document to the index
*
* @param Apache_Solr_Document $document
* @param boolean $allowDups
* @param boolean $overwritePending
* @param boolean $overwriteCommitted
* @return Apache_Solr_Response
*
* @throws Apache_Solr_HttpTransportException If an error occurs during the service call
*/
public function addDocument(Apache_Solr_Document $document, $allowDups = false, $overwritePending = true, $overwriteCommitted = true)
{
$service = $this->_selectWriteService();
do
{
try
{
return $service->addDocument($document, $allowDups, $overwritePending, $overwriteCommitted);
}
catch (Apache_Solr_HttpTransportException $e)
{
if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR
{
throw $e;
}
}
$service = $this->_selectWriteService(true);
} while ($service);
return false;
}
/**
* Add an array of Solr Documents to the index all at once
*
* @param array $documents Should be an array of Apache_Solr_Document instances
* @param boolean $allowDups
* @param boolean $overwritePending
* @param boolean $overwriteCommitted
* @return Apache_Solr_Response
*
* @throws Apache_Solr_HttpTransportException If an error occurs during the service call
*/
public function addDocuments($documents, $allowDups = false, $overwritePending = true, $overwriteCommitted = true)
{
$service = $this->_selectWriteService();
do
{
try
{
return $service->addDocuments($documents, $allowDups, $overwritePending, $overwriteCommitted);
}
catch (Apache_Solr_HttpTransportException $e)
{
if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR
{
throw $e;
}
}
$service = $this->_selectWriteService(true);
} while ($service);
return false;
}
/**
* Send a commit command. Will be synchronous unless both wait parameters are set
* to false.
*
* @param boolean $waitFlush
* @param boolean $waitSearcher
* @return Apache_Solr_Response
*
* @throws Apache_Solr_HttpTransportException If an error occurs during the service call
*/
public function commit($optimize = true, $waitFlush = true, $waitSearcher = true, $timeout = 3600)
{
$service = $this->_selectWriteService();
do
{
try
{
return $service->commit($optimize, $waitFlush, $waitSearcher, $timeout);
}
catch (Apache_Solr_HttpTransportException $e)
{
if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR
{
throw $e;
}
}
$service = $this->_selectWriteService(true);
} while ($service);
return false;
}
/**
* Raw Delete Method. Takes a raw post body and sends it to the update service. Body should be
* a complete and well formed "delete" xml document
*
* @param string $rawPost
* @param float $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception)
* @return Apache_Solr_Response
*
* @throws Apache_Solr_HttpTransportException If an error occurs during the service call
*/
public function delete($rawPost, $timeout = 3600)
{
$service = $this->_selectWriteService();
do
{
try
{
return $service->delete($rawPost, $timeout);
}
catch (Apache_Solr_HttpTransportException $e)
{
if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR
{
throw $e;
}
}
$service = $this->_selectWriteService(true);
} while ($service);
return false;
}
/**
* Create a delete document based on document ID
*
* @param string $id
* @param boolean $fromPending
* @param boolean $fromCommitted
* @param float $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception)
* @return Apache_Solr_Response
*
* @throws Apache_Solr_HttpTransportException If an error occurs during the service call
*/
public function deleteById($id, $fromPending = true, $fromCommitted = true, $timeout = 3600)
{
$service = $this->_selectWriteService();
do
{
try
{
return $service->deleteById($id, $fromPending, $fromCommitted, $timeout);
}
catch (Apache_Solr_HttpTransportException $e)
{
if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR
{
throw $e;
}
}
$service = $this->_selectWriteService(true);
} while ($service);
return false;
}
/**
* Create and post a delete document based on multiple document IDs.
*
* @param array $ids Expected to be utf-8 encoded strings
* @param boolean $fromPending
* @param boolean $fromCommitted
* @param float $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception)
* @return Apache_Solr_Response
*
* @throws Apache_Solr_HttpTransportException If an error occurs during the service call
*/
public function deleteByMultipleIds($ids, $fromPending = true, $fromCommitted = true, $timeout = 3600)
{
$service = $this->_selectWriteService();
do
{
try
{
return $service->deleteByMultipleId($ids, $fromPending, $fromCommitted, $timeout);
}
catch (Apache_Solr_HttpTransportException $e)
{
if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR
{
throw $e;
}
}
$service = $this->_selectWriteService(true);
} while ($service);
return false;
}
/**
* Create a delete document based on a query and submit it
*
* @param string $rawQuery
* @param boolean $fromPending
* @param boolean $fromCommitted
* @param float $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception)
* @return Apache_Solr_Response
*
* @throws Apache_Solr_HttpTransportException If an error occurs during the service call
*/
public function deleteByQuery($rawQuery, $fromPending = true, $fromCommitted = true, $timeout = 3600)
{
$service = $this->_selectWriteService();
do
{
try
{
return $service->deleteByQuery($rawQuery, $fromPending, $fromCommitted, $timeout);
}
catch (Apache_Solr_HttpTransportException $e)
{
if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR
{
throw $e;
}
}
$service = $this->_selectWriteService(true);
} while ($service);
return false;
}
/**
* Use Solr Cell to extract document contents. See {@link http://wiki.apache.org/solr/ExtractingRequestHandler} for information on how
* to use Solr Cell and what parameters are available.
*
* NOTE: when passing an Apache_Solr_Document instance, field names and boosts will automatically be prepended by "literal." and "boost."
* as appropriate. Any keys from the $params array will NOT be treated this way. Any mappings from the document will overwrite key / value
* 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
* pass in a document isntance with an "id" field" - the document's value(s) will take precedence).
*
* @param string $file Path to file to extract data from
* @param array $params optional array of key value pairs that will be sent with the post (see Solr Cell documentation)
* @param Apache_Solr_Document $document optional document that will be used to generate post parameters (literal.* and boost.* params)
* @param string $mimetype optional mimetype specification (for the file being extracted)
*
* @return Apache_Solr_Response
*
* @throws Apache_Solr_InvalidArgumentException if $file, $params, or $document are invalid.
*/
public function extract($file, $params = array(), $document = null, $mimetype = 'application/octet-stream')
{
$service = $this->_selectWriteService();
do
{
try
{
return $service->extract($file, $params, $document, $mimetype);
}
catch (Apache_Solr_HttpTransportException $e)
{
if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR
{
throw $e;
}
}
$service = $this->_selectWriteService(true);
} while ($service);
return false;
}
/**
* Use Solr Cell to extract document contents. See {@link http://wiki.apache.org/solr/ExtractingRequestHandler} for information on how
* to use Solr Cell and what parameters are available.
*
* NOTE: when passing an Apache_Solr_Document instance, field names and boosts will automatically be prepended by "literal." and "boost."
* as appropriate. Any keys from the $params array will NOT be treated this way. Any mappings from the document will overwrite key / value
* 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
* pass in a document isntance with an "id" field" - the document's value(s) will take precedence).
*
* @param string $data Data that will be passed to Solr Cell
* @param array $params optional array of key value pairs that will be sent with the post (see Solr Cell documentation)
* @param Apache_Solr_Document $document optional document that will be used to generate post parameters (literal.* and boost.* params)
* @param string $mimetype optional mimetype specification (for the file being extracted)
*
* @return Apache_Solr_Response
*
* @throws Apache_Solr_InvalidArgumentException if $file, $params, or $document are invalid.
*
* @todo Should be using multipart/form-data to post parameter values, but I could not get my implementation to work. Needs revisisted.
*/
public function extractFromString($data, $params = array(), $document = null, $mimetype = 'application/octet-stream')
{
$service = $this->_selectWriteService();
do
{
try
{
return $service->extractFromString($data, $params, $document, $mimetype);
}
catch (Apache_Solr_HttpTransportException $e)
{
if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR
{
throw $e;
}
}
$service = $this->_selectWriteService(true);
} while ($service);
return false;
}
/**
* Send an optimize command. Will be synchronous unless both wait parameters are set
* to false.
*
* @param boolean $waitFlush
* @param boolean $waitSearcher
* @param float $timeout Maximum expected duration of the optimize operation on the server (otherwise, will throw a communication exception)
* @return Apache_Solr_Response
*
* @throws Apache_Solr_HttpTransportException If an error occurs during the service call
*/
public function optimize($waitFlush = true, $waitSearcher = true, $timeout = 3600)
{
$service = $this->_selectWriteService();
do
{
try
{
return $service->optimize($waitFlush, $waitSearcher, $timeout);
}
catch (Apache_Solr_HttpTransportException $e)
{
if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR
{
throw $e;
}
}
$service = $this->_selectWriteService(true);
} while ($service);
return false;
}
/**
* Simple Search interface
*
* @param string $query The raw query string
* @param int $offset The starting offset for result documents
* @param int $limit The maximum number of result documents to return
* @param array $params key / value pairs for query parameters, use arrays for multivalued parameters
* @param string $method The HTTP method (Apache_Solr_Service::METHOD_GET or Apache_Solr_Service::METHOD::POST)
* @return Apache_Solr_Response
*
* @throws Apache_Solr_HttpTransportException If an error occurs during the service call
*/
public function search($query, $offset = 0, $limit = 10, $params = array(), $method = Apache_Solr_Service::METHOD_GET)
{
$service = $this->_selectReadService();
do
{
try
{
return $service->search($query, $offset, $limit, $params, $method);
}
catch (Apache_Solr_HttpTransportException $e)
{
if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR
{
throw $e;
}
}
$service = $this->_selectReadService(true);
} while ($service);
return false;
}
}

26
thirdparty/solr-php-client/COPYING vendored Normal file
View File

@ -0,0 +1,26 @@
Copyright (c) 2007-2013, PTC Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of PTC Inc. nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

15
thirdparty/solr-php-client/README.md vendored Normal file
View File

@ -0,0 +1,15 @@
# Solr PHP Client
A purely PHP library for indexing and searching documents against an Apache Solr installation.
This project was formerly maintained at [http://code.google.com/p/solr-php-client](http://code.google.com/p/solr-php-client). Previous issues and downloads are still available for viewing there.
## Need Help?
Try starting with the [FAQ](https://github.com/PTCInc/solr-php-client/wiki/FAQ) and [Example Usage](https://github.com/PTCInc/solr-php-client/wiki/Example-Usage).
Also, feel free to search and ask questions on the google mailing list: [php-solr-client@googlegroups.com](mailto:php-solr-client@googlegroups.com) / [Group Page](https://groups.google.com/forum/?fromgroups#!forum/php-solr-client)
## License
Code is released under a 3-Clause BSD license, see [COPYING](https://github.com/PTCInc/solr-php-client/blob/master/COPYING) for full text.

View File

@ -0,0 +1,17 @@
{
"name": "ptcinc/solr-php-client",
"description": "A purely PHP library for indexing and searching documents against an Apache Solr installation",
"keywords": ["php", "solr", "client"],
"license": "BSD-3-Clause",
"authors": [
{
"name": "Donovan Jimenez",
"homepage": "https://github.com/djimenez"
}
],
"autoload": {
"psr-0": {
"Apache_Solr_": ""
}
}
}

View File

@ -0,0 +1,439 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Donovan Jimenez <djimenez@conduit-it.com>
*/
/**
* Apache_Solr_Document Unit Test
*/
class Apache_Solr_DocumentTest extends PHPUnit_Framework_TestCase
{
/**
* Fixture used for testing
*
* @var Apache_Solr_Document
*/
private $_fixture;
/**
* Setup for the fixture before each unit test - part of test case API
*/
protected function setup()
{
$this->_fixture = new Apache_Solr_Document();
}
/**
* Teardown after each unit test - part of test case API
*/
protected function tearDown()
{
unset($this->_fixture);
}
public function testDefaultStateAfterConstructor()
{
// document boost should be false
$this->assertFalse($this->_fixture->getBoost());
// document fields should be empty
$this->assertEquals(0, count($this->_fixture->getFieldNames()));
$this->assertEquals(0, count($this->_fixture->getFieldValues()));
$this->assertEquals(0, count($this->_fixture->getFieldBoosts()));
// document iterator should be empty
$this->assertEquals(0, iterator_count($this->_fixture));
}
public function testSetAndGetField()
{
$field = 'field';
$value = 'value';
$boost = 0.5;
// set the field
$this->_fixture->setField($field, $value, $boost);
$result = $this->_fixture->getField($field);
// check the array values
$this->assertTrue(is_array($result));
$this->assertEquals($field, $result['name']);
$this->assertEquals($value, $result['value']);
$this->assertEquals($boost, $result['boost']);
}
public function testGetFieldReturnsFalseForNonExistentField()
{
$this->assertFalse($this->_fixture->getField('field'));
}
public function testMagicGetForFieldValues()
{
$field = 'field';
$value = 'value';
$this->_fixture->setField($field, $value);
// test the __get value
$this->assertEquals($value, $this->_fixture->{$field});
}
/**
* Added for issue #48 (http://code.google.com/p/solr-php-client/issues/detail?id=48)
*/
public function testMagicGetReturnsNullForNonExistentField()
{
$this->assertNull($this->_fixture->nonExistent);
}
public function testMagicSetForFieldValues()
{
$field = 'field';
$value = 'value';
// set field value with magic __set
$this->_fixture->{$field} = $value;
$fieldArray = $this->_fixture->getField($field);
// set values
$this->assertEquals($field, $fieldArray['name']);
$this->assertEquals($value, $fieldArray['value']);
$this->assertTrue($fieldArray['boost'] === false);
}
public function testMagicIssetForNonExistentField()
{
$this->assertFalse(isset($this->_fixture->field));
}
public function testMagicIssetForExistingField()
{
$field = 'field';
$this->_fixture->{$field} = 'value';
$this->assertTrue(isset($this->_fixture->{$field}));
}
public function testMagicUnsetForExistingField()
{
$field = 'field';
$this->_fixture->{$field} = 'value';
// now unset the field
unset($this->_fixture->{$field});
// now test that its unset
$this->assertFalse(isset($this->_fixture->{$field}));
}
public function testMagicUnsetForNonExistingField()
{
$field = 'field';
unset($this->_fixture->{$field});
// now test that it still does not exist
$this->assertFalse(isset($this->_fixture->{$field}));
}
public function testSetAndGetFieldBoostWithPositiveNumberSetsBoost()
{
$field = 'field';
$boost = 0.5;
$this->_fixture->setFieldBoost($field, $boost);
// test the field boost
$this->assertEquals($boost, $this->_fixture->getFieldBoost($field));
}
public function testSetAndGetFieldBoostWithZeroRemovesBoost()
{
$field = 'field';
$boost = 0;
$this->_fixture->setFieldBoost($field, $boost);
// test the field boost
$this->assertTrue($this->_fixture->getFieldBoost($field) === false);
}
public function testSetAndGetFieldBoostWithNegativeNumberRemovesBoost()
{
$field = 'field';
$boost = -1;
$this->_fixture->setFieldBoost($field, $boost);
// test the field boost
$this->assertTrue($this->_fixture->getFieldBoost($field) === false);
}
public function testSetAndGetFieldBoostWithNonNumberRemovesBoost()
{
$field = 'field';
$boost = "i am not a number";
$this->_fixture->setFieldBoost($field, $boost);
// test the field boost
$this->assertTrue($this->_fixture->getFieldBoost($field) === false);
}
public function testSetAndGetBoostWithPositiveNumberSetsBoost()
{
$boost = 0.5;
$this->_fixture->setBoost($boost);
// the boost should now be set
$this->assertEquals($boost, $this->_fixture->getBoost());
}
public function testSetAndGetBoostWithZeroRemovesBoost()
{
$this->_fixture->setBoost(0);
// should be boolean false
$this->assertTrue($this->_fixture->getBoost() === false);
}
public function testSetAndGetBoostWithNegativeNumberRemovesBoost()
{
$this->_fixture->setBoost(-1);
// should be boolean false
$this->assertTrue($this->_fixture->getBoost() === false);
}
public function testSetAndGetBoostWithNonNumberRemovesBoost()
{
$this->_fixture->setBoost("i am not a number");
// should be boolean false
$this->assertTrue($this->_fixture->getBoost() === false);
}
public function testAddFieldCreatesMultiValueWhenFieldDoesNotExist()
{
$field = 'field';
$value = 'value';
$this->_fixture->addField($field, $value);
// check that value is an array with correct values
$fieldValue = $this->_fixture->{$field};
$this->assertTrue(is_array($fieldValue));
$this->assertEquals(1, count($fieldValue));
$this->assertEquals($value, $fieldValue[0]);
}
/**
* setMultiValue has been deprecated and defers to addField
*
* @deprecated
*/
public function testSetMultiValueCreateMultiValueWhenFieldDoesNotExist()
{
$field = 'field';
$value = 'value';
$this->_fixture->setMultiValue($field, $value);
// check that value is an array with correct values
$fieldValue = $this->_fixture->{$field};
$this->assertTrue(is_array($fieldValue));
$this->assertEquals(1, count($fieldValue));
$this->assertEquals($value, $fieldValue[0]);
}
public function testAddFieldCreatesMultiValueWhenFieldDoesExistAsSingleValue()
{
$field = 'field';
$value1 = 'value1';
$value2 = 'value2';
// set first value as singular value
$this->_fixture->{$field} = $value1;
// add a second value with addField
$this->_fixture->addField($field, $value2);
// check that value is an array with correct values
$fieldValue = $this->_fixture->{$field};
$this->assertTrue(is_array($fieldValue));
$this->assertEquals(2, count($fieldValue));
$this->assertEquals($value1, $fieldValue[0]);
$this->assertEquals($value2, $fieldValue[1]);
}
/**
* setMultiValue has been deprecated and defers to addField
*
* @deprecated
*/
public function testSetMultiValueCreatesMultiValueWhenFieldDoesExistAsSingleValue()
{
$field = 'field';
$value1 = 'value1';
$value2 = 'value2';
// set first value as singular value
$this->_fixture->{$field} = $value1;
// add a second value with addField
$this->_fixture->setMultiValue($field, $value2);
// check that value is an array with correct values
$fieldValue = $this->_fixture->{$field};
$this->assertTrue(is_array($fieldValue));
$this->assertEquals(2, count($fieldValue));
$this->assertEquals($value1, $fieldValue[0]);
$this->assertEquals($value2, $fieldValue[1]);
}
public function testAddFieldWithBoostSetsFieldBoost()
{
$field = 'field';
$boost = 0.5;
$this->_fixture->addField($field, 'value', $boost);
// check the field boost
$this->assertEquals($boost, $this->_fixture->getFieldBoost($field));
}
public function testAddFieldWithBoostMultipliesWithAPreexistingBoost()
{
$field = 'field';
$boost = 0.5;
// set a field with a boost
$this->_fixture->setField($field, 'value1', $boost);
// now add another value with the same boost
$this->_fixture->addField($field, 'value2', $boost);
// new boost should be $boost * $boost
$this->assertEquals($boost * $boost, $this->_fixture->getFieldBoost($field));
}
public function testGetFieldNamesIsInitiallyEmpty()
{
$fieldNames = $this->_fixture->getFieldNames();
$this->assertTrue(empty($fieldNames));
}
public function testGetFieldNamesAfterFieldIsSetIsNotEmpty()
{
$field = 'field';
$this->_fixture->{$field} = 'value';
$fieldNames = $this->_fixture->getFieldNames();
$this->assertTrue(!empty($fieldNames));
$this->assertEquals(1, count($fieldNames));
$this->assertEquals($field, $fieldNames[0]);
}
public function testGetFieldValuesIsInitiallyEmpty()
{
$fieldValues = $this->_fixture->getFieldValues();
$this->assertTrue(empty($fieldValues));
}
public function testGetFieldValuessAfterFieldIsSetIsNotEmpty()
{
$value = 'value';
$this->_fixture->field = $value;
$fieldValues = $this->_fixture->getFieldValues();
$this->assertTrue(!empty($fieldValues));
$this->assertEquals(1, count($fieldValues));
$this->assertEquals($value, $fieldValues[0]);
}
public function testGetIteratorAfterFieldValueIsSet()
{
$field = 'field';
$value = 'value';
$this->_fixture->{$field} = $value;
$itemCount = 0;
foreach ($this->_fixture as $iteratedField => $iteratedValue)
{
++$itemCount;
// test field and value
$this->assertEquals($field, $iteratedField);
$this->assertEquals($value, $iteratedValue);
}
// test number of iterations is 1
$this->assertEquals(1, $itemCount);
}
public function testClearReturnsDocumentToDefaultState()
{
// set the document boost
$this->_fixture->setBoost(0.5);
// set a field
$this->_fixture->someField = "some value";
// clear the document to remove boost and fields
$this->_fixture->clear();
// document boost should now be false
$this->assertFalse($this->_fixture->getBoost());
// document fields should now be empty
$this->assertEquals(0, count($this->_fixture->getFieldNames()));
$this->assertEquals(0, count($this->_fixture->getFieldValues()));
$this->assertEquals(0, count($this->_fixture->getFieldBoosts()));
// document iterator should now be empty
$this->assertEquals(0, iterator_count($this->_fixture));
}
}

View File

@ -0,0 +1,208 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Donovan Jimenez <djimenez@conduit-it.com>
*/
/**
* Apache_Solr_HttpTransport_Abstract Unit Tests
*/
abstract class Apache_Solr_HttpTransport_AbstractTest extends PHPUnit_Framework_TestCase
{
const TIMEOUT = 2;
// request our copyright file from googlecode for GET and HEAD
const GET_URL = "http://solr-php-client.googlecode.com/svn/trunk/COPYING";
const GET_RESPONSE_MIME_TYPE = 'text/plain';
const GET_RESPONSE_ENCODING = 'UTF-8';
const GET_RESPONSE_MATCH = 'Copyright (c) ';
// post to the issue list page with a search for 'meh'
const POST_URL = "http://code.google.com/p/solr-php-client/issues/list";
const POST_DATA = "can=2&q=meh&colspec=ID+Type+Status+Priority+Milestone+Owner+Summary&cells=tiles";
const POST_REQUEST_CONTENT_TYPE = 'application/x-www-form-urlencoded; charset=UTF-8';
const POST_RESPONSE_MIME_TYPE = 'text/html';
const POST_RESPONSE_ENCODING = 'UTF-8';
//const POST_RESPONSE_MATCH = 'not sure';
abstract public function getFixture();
public function testGetDefaultTimeoutWithDefaultConstructor()
{
$fixture = $this->getFixture();
$timeout = $fixture->getDefaultTimeout();
$this->assertGreaterThan(0, $timeout);
}
public function testGetDefaultTimeoutSetToSixtyForBadValues()
{
// first set our default_socket_timeout ini setting
$previousValue = ini_get('default_socket_timeout');
ini_set('default_socket_timeout', 0);
$fixture = $this->getFixture();
$timeout = $fixture->getDefaultTimeout();
// reset timeout
ini_set('default_socket_timeout', $previousValue);
$this->assertEquals(60, $timeout);
}
public function testSetDefaultTimeout()
{
$newTimeout = 1234;
$fixture = $this->getFixture();
$fixture->setDefaultTimeout($newTimeout);
$timeout = $fixture->getDefaultTimeout();
$this->assertEquals($newTimeout, $timeout);
}
public function testPerformGetRequest()
{
$fixture = $this->getFixture();
$fixture->setDefaultTimeout(self::TIMEOUT);
$response = $fixture->performGetRequest(self::GET_URL);
$this->assertInstanceOf('Apache_Solr_HttpTransport_Response', $response);
$this->assertEquals(200, $response->getStatusCode(), 'Status code was not 200');
$this->assertEquals(self::GET_RESPONSE_MIME_TYPE, $response->getMimeType(), 'mimetype was not correct');
$this->assertEquals(self::GET_RESPONSE_ENCODING, $response->getEncoding(), 'character encoding was not correct');
$this->assertStringStartsWith(self::GET_RESPONSE_MATCH, $response->getBody(), 'body did not start with match text');
}
public function testPerformGetRequestWithTimeout()
{
$fixture = $this->getFixture();
$response = $fixture->performGetRequest(self::GET_URL, self::TIMEOUT);
$this->assertInstanceOf('Apache_Solr_HttpTransport_Response', $response);
$this->assertEquals(200, $response->getStatusCode(), 'Status code was not 200');
$this->assertEquals(self::GET_RESPONSE_MIME_TYPE, $response->getMimeType(), 'mimetype was not correct');
$this->assertEquals(self::GET_RESPONSE_ENCODING, $response->getEncoding(), 'character encoding was not correct');
$this->assertStringStartsWith(self::GET_RESPONSE_MATCH, $response->getBody(), 'body did not start with match text');
}
public function testPerformHeadRequest()
{
$fixture = $this->getFixture();
$fixture->setDefaultTimeout(self::TIMEOUT);
$response = $fixture->performHeadRequest(self::GET_URL);
// we should get everything the same as a get, except the body
$this->assertInstanceOf('Apache_Solr_HttpTransport_Response', $response);
$this->assertEquals(200, $response->getStatusCode(), 'Status code was not 200');
$this->assertEquals(self::GET_RESPONSE_MIME_TYPE, $response->getMimeType(), 'mimetype was not correct');
$this->assertEquals(self::GET_RESPONSE_ENCODING, $response->getEncoding(), 'character encoding was not correct');
$this->assertEquals("", $response->getBody(), 'body was not empty');
}
public function testPerformHeadRequestWithTimeout()
{
$fixture = $this->getFixture();
$response = $fixture->performHeadRequest(self::GET_URL, self::TIMEOUT);
// we should get everything the same as a get, except the body
$this->assertInstanceOf('Apache_Solr_HttpTransport_Response', $response);
$this->assertEquals(200, $response->getStatusCode(), 'Status code was not 200');
$this->assertEquals(self::GET_RESPONSE_MIME_TYPE, $response->getMimeType(), 'mimetype was not correct');
$this->assertEquals(self::GET_RESPONSE_ENCODING, $response->getEncoding(), 'character encoding was not correct');
$this->assertEquals("", $response->getBody(), 'body was not empty');
}
public function testPerformPostRequest()
{
$fixture = $this->getFixture();
$fixture->setDefaultTimeout(self::TIMEOUT);
$response = $fixture->performPostRequest(self::POST_URL, self::POST_DATA, self::POST_REQUEST_CONTENT_TYPE);
$this->assertInstanceOf('Apache_Solr_HttpTransport_Response', $response);
$this->assertEquals(200, $response->getStatusCode(), 'Status code was not 200');
$this->assertEquals(self::POST_RESPONSE_MIME_TYPE, $response->getMimeType(), 'mimetype was not correct');
$this->assertEquals(self::POST_RESPONSE_ENCODING, $response->getEncoding(), 'character encoding was not correct');
//$this->assertStringStartsWith(self::POST_RESPONSE_MATCH, $response->getBody(), 'body did not start with match text');
}
public function testPerformPostRequestWithTimeout()
{
$fixture = $this->getFixture();
$response = $fixture->performPostRequest(self::POST_URL, self::POST_DATA, self::POST_REQUEST_CONTENT_TYPE, self::TIMEOUT);
$this->assertInstanceOf('Apache_Solr_HttpTransport_Response', $response);
$this->assertEquals(200, $response->getStatusCode(), 'Status code was not 200');
$this->assertEquals(self::POST_RESPONSE_MIME_TYPE, $response->getMimeType(), 'mimetype was not correct');
$this->assertEquals(self::POST_RESPONSE_ENCODING, $response->getEncoding(), 'character encoding was not correct');
//$this->assertStringStartsWith(self::POST_RESPONSE_MATCH, $response->getBody(), 'body did not start with match text');
}
/**
* Test one session doing multiple requests in multiple orders
*/
public function testMultipleRequests()
{
// initial get request
$this->testPerformGetRequest();
// head following get
$this->testPerformHeadRequest();
// post following head
$this->testPerformPostRequest();
// get following post
$this->testPerformGetRequest();
// post following get
$this->testPerformPostRequest();
// head following post
$this->testPerformHeadRequest();
// get following post
$this->testPerformGetRequest();
}
}

View File

@ -0,0 +1,53 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Donovan Jimenez <djimenez@conduit-it.com>
*/
/**
* Apache_Solr_HttpTransport_CurlNoReuse Unit Tests
*/
class Apache_Solr_HttpTransport_CurlNoReuseTest extends Apache_Solr_HttpTransport_AbstractTest
{
public function getFixture()
{
// ensure curl is enabled
if (!extension_loaded('curl'))
{
$this->markTestSkipped("curl module is not enabled");
}
return new Apache_Solr_HttpTransport_CurlNoReuse();
}
}

View File

@ -0,0 +1,53 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Donovan Jimenez <djimenez@conduit-it.com>
*/
/**
* Apache_Solr_HttpTransport_Curl Unit Tests
*/
class Apache_Solr_HttpTransport_CurlTest extends Apache_Solr_HttpTransport_AbstractTest
{
public function getFixture()
{
// ensure curl is enabled
if (!extension_loaded('curl'))
{
$this->markTestSkipped("curl module is not enabled");
}
return new Apache_Solr_HttpTransport_Curl();
}
}

View File

@ -0,0 +1,53 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Donovan Jimenez <djimenez@conduit-it.com>
*/
/**
* Apache_Solr_HttpTransport_FileGetContents Unit Tests
*/
class Apache_Solr_HttpTransport_FileGetContentsTest extends Apache_Solr_HttpTransport_AbstractTest
{
public function getFixture()
{
// make sure allow_url_fopen is on
if (!ini_get("allow_url_fopen"))
{
$this->markTestSkipped("allow_url_fopen is not enabled");
}
return new Apache_Solr_HttpTransport_FileGetContents();
}
}

View File

@ -0,0 +1,164 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Donovan Jimenez <djimenez@conduit-it.com>
*/
/**
* Apache_Solr_HttpTransport_Response Unit Tests
*/
class Apache_Solr_HttpTransport_ResponseTest extends PHPUnit_Framework_TestCase
{
// generated with the following query string: select?q=solr&wt=json
const STATUS_CODE_200 = 200;
const STATUS_MESSAGE_200 = "OK";
const BODY_200 = '{"responseHeader":{"status":0,"QTime":0,"params":{"q":"solr","wt":"json"}},"response":{"numFound":0,"start":0,"docs":[]}}';
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]}]}}';
const CONTENT_TYPE_200 = "text/plain; charset=utf-8";
const MIME_TYPE_200 = "text/plain";
const ENCODING_200 = "utf-8";
// generated with the following query string: select?qt=standad&q=solr&wt=json
// NOTE: the intentional mispelling of the standard in the qt parameter
const STATUS_CODE_400 = 400;
const STATUS_MESSAGE_400 = "Bad Request";
const BODY_400 = '<html><head><title>Apache Tomcat/6.0.24 - Error report</title><style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style> </head><body><h1>HTTP Status 400 - unknown handler: standad</h1><HR size="1" noshade="noshade"><p><b>type</b> Status report</p><p><b>message</b> <u>unknown handler: standad</u></p><p><b>description</b> <u>The request sent by the client was syntactically incorrect (unknown handler: standad).</u></p><HR size="1" noshade="noshade"><h3>Apache Tomcat/6.0.24</h3></body></html>';
const CONTENT_TYPE_400 = "text/html; charset=utf-8";
const MIME_TYPE_400 = "text/html";
const ENCODING_400 = "utf-8";
// generated with the following query string: select?q=solr&wt=json on a core that does not exist
const STATUS_CODE_404 = 404;
const STATUS_MESSAGE_404 = "Not Found";
const BODY_404 = '<html><head><title>Apache Tomcat/6.0.24 - Error report</title><style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style> </head><body><h1>HTTP Status 404 - /solr/doesnotexist/select</h1><HR size="1" noshade="noshade"><p><b>type</b> Status report</p><p><b>message</b> <u>/solr/doesnotexist/select</u></p><p><b>description</b> <u>The requested resource (/solr/doesnotexist/select) is not available.</u></p><HR size="1" noshade="noshade"><h3>Apache Tomcat/6.0.24</h3></body></html>';
const CONTENT_TYPE_404 = "text/html; charset=utf-8";
const MIME_TYPE_404 = "text/html";
const ENCODING_404 = "utf-8";
public static function get0Response()
{
return new Apache_Solr_HttpTransport_Response(null, null, null);
}
public static function get200Response()
{
return new Apache_Solr_HttpTransport_Response(self::STATUS_CODE_200, self::CONTENT_TYPE_200, self::BODY_200);
}
public static function get200ResponseWithDocuments()
{
return new Apache_Solr_HttpTransport_Response(self::STATUS_CODE_200, self::CONTENT_TYPE_200, self::BODY_200_WITH_DOCUMENTS);
}
public static function get400Response()
{
return new Apache_Solr_HttpTransport_Response(self::STATUS_CODE_400, self::CONTENT_TYPE_400, self::BODY_400);
}
public static function get404Response()
{
return new Apache_Solr_HttpTransport_Response(self::STATUS_CODE_404, self::CONTENT_TYPE_404, self::BODY_404);
}
public function testGetStatusCode()
{
$fixture = self::get200Response();
$statusCode = $fixture->getStatusCode();
$this->assertEquals(self::STATUS_CODE_200, $statusCode);
}
public function testGetStatusMessage()
{
$fixture = self::get200Response();
$statusMessage = $fixture->getStatusMessage();
$this->assertEquals(self::STATUS_MESSAGE_200, $statusMessage);
}
public function testGetStatusMessageWithUnknownCode()
{
$fixture = new Apache_Solr_HttpTransport_Response(499, null, null);
$statusMessage = $fixture->getStatusMessage();
$this->assertEquals("Unknown Status", $statusMessage);
}
public function testGetBody()
{
$fixture = self::get200Response();
$body = $fixture->getBody();
$this->assertEquals(self::BODY_200, $body);
}
public function testGetMimeType()
{
$fixture = self::get200Response();
$mimeType = $fixture->getMimeType();
$this->assertEquals(self::MIME_TYPE_200, $mimeType);
}
public function testGetEncoding()
{
$fixture = self::get200Response();
$encoding = $fixture->getEncoding();
$this->assertEquals(self::ENCODING_200, $encoding);
}
public function testGetStatusMessageWhenNotProvided()
{
// test 4 of the most common status code responses, probably don't need
// to test all the codes we have
$fixture = new Apache_Solr_HttpTransport_Response(null, null, null, null, null);
$this->assertEquals("Communication Error", $fixture->getStatusMessage(), 'Did not get correct default status message for status code 0');
$fixture = new Apache_Solr_HttpTransport_Response(200, null, null, null, null);
$this->assertEquals("OK", $fixture->getStatusMessage(), 'Did not get correct default status message for status code 200');
$fixture = new Apache_Solr_HttpTransport_Response(400, null, null, null, null);
$this->assertEquals("Bad Request", $fixture->getStatusMessage(), 'Did not get correct default status message for status code 400');
$fixture = new Apache_Solr_HttpTransport_Response(404, null, null, null, null);
$this->assertEquals("Not Found", $fixture->getStatusMessage(), 'Did not get correct default status message for status code 404');
}
}

View File

@ -0,0 +1,58 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Donovan Jimenez <djimenez@conduit-it.com>
*/
/**
* Apache_Solr_HttpTransportException Unit Tests
*/
class Apache_Solr_HttpTransportExceptionTest extends PHPUnit_Framework_TestCase
{
/**
* @expectedException PHPUnit_Framework_Error
*/
public function testConstructorRequiresResponse()
{
$fixture = new Apache_Solr_HttpTransportException();
}
public function testGetResponse()
{
$response = Apache_Solr_ResponseTest::get0Response();
$fixture = new Apache_Solr_HttpTransportException($response);
$this->assertEquals($response, $fixture->getResponse());
}
}

View File

@ -0,0 +1,194 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Donovan Jimenez <djimenez@conduit-it.com>
*/
/**
* Apache_Solr_Response Unit Test
*/
class Apache_Solr_ResponseTest extends PHPUnit_Framework_TestCase
{
static public function get0Response($createDocuments = true, $collapseSingleValueArrays = true)
{
return new Apache_Solr_Response(Apache_Solr_HttpTransport_ResponseTest::get0Response(), $createDocuments, $collapseSingleValueArrays);
}
static public function get200Response($createDocuments = true, $collapseSingleValueArrays = true)
{
return new Apache_Solr_Response(Apache_Solr_HttpTransport_ResponseTest::get200Response(), $createDocuments, $collapseSingleValueArrays);
}
static public function get200ResponseWithDocuments($createDocuments = true, $collapseSingleValueArrays = true)
{
return new Apache_Solr_Response(Apache_Solr_HttpTransport_ResponseTest::get200ResponseWithDocuments(), $createDocuments, $collapseSingleValueArrays);
}
static public function get400Response($createDocuments = true, $collapseSingleValueArrays = true)
{
return new Apache_Solr_Response(Apache_Solr_HttpTransport_ResponseTest::get400Response(), $createDocuments, $collapseSingleValueArrays);
}
static public function get404Response($createDocuments = true, $collapseSingleValueArrays = true)
{
return new Apache_Solr_Response(Apache_Solr_HttpTransport_ResponseTest::get404Response(), $createDocuments, $collapseSingleValueArrays);
}
public function testConstuctorWithValidBodyAndHeaders()
{
$fixture = self::get200Response();
// check that we parsed the HTTP status correctly
$this->assertEquals(Apache_Solr_HttpTransport_ResponseTest::STATUS_CODE_200, $fixture->getHttpStatus());
// check that we received the body correctly
$this->assertEquals(Apache_Solr_HttpTransport_ResponseTest::BODY_200, $fixture->getRawResponse());
// check that our defaults are correct
$this->assertEquals(Apache_Solr_HttpTransport_ResponseTest::ENCODING_200, $fixture->getEncoding());
$this->assertEquals(Apache_Solr_HttpTransport_ResponseTest::MIME_TYPE_200, $fixture->getType());
}
public function testConstructorWithBadBodyAndHeaders()
{
$fixture = self::get0Response();
// check that our defaults are correct
$this->assertEquals(0, $fixture->getHttpStatus());
$this->assertEquals("UTF-8", $fixture->getEncoding());
$this->assertEquals("text/plain", $fixture->getType());
}
public function testMagicGetWithValidBodyAndHeaders()
{
$fixture = self::get200Response();
// test top level gets
$this->assertInstanceOf('stdClass', $fixture->responseHeader);
$this->assertEquals(0, $fixture->responseHeader->status);
$this->assertEquals(0, $fixture->responseHeader->QTime);
$this->assertInstanceOf('stdClass', $fixture->response);
$this->assertEquals(0, $fixture->response->numFound);
$this->assertTrue(is_array($fixture->response->docs));
$this->assertEquals(0, count($fixture->response->docs));
}
/**
* @expectedException Apache_Solr_ParserException
*/
public function testMagicGetWith0Response()
{
$fixture = self::get0Response();
// attempting to magic get a part of the response
// should throw a ParserException
$fixture->responseHeader;
$this->fail("Expected Apache_Solr_ParserException was not raised");
}
/**
* @expectedException Apache_Solr_ParserException
*/
public function testMagicGetWith400Response()
{
$fixture = self::get400Response();
// attempting to magic get a part of the response
// should throw a ParserException
$fixture->responseHeader;
$this->fail("Expected Apache_Solr_ParserException was not raised");
}
/**
* @expectedException Apache_Solr_ParserException
*/
public function testMagicGetWith404Response()
{
$fixture = self::get404Response();
// attempting to magic get a part of the response
// should throw a ParserException
$fixture->responseHeader;
$this->fail("Expected Apache_Solr_ParserException was not raised");
}
public function testCreateDocuments()
{
$fixture = self::get200ResponseWithDocuments();
$this->assertTrue(count($fixture->response->docs) > 0, 'There are not 1 or more documents, cannot test');
$this->assertInstanceOf('Apache_Solr_Document', $fixture->response->docs[0], 'The first document is not of type Apache_Solr_Document');
}
public function testDontCreateDocuments()
{
$fixture = self::get200ResponseWithDocuments(false);
$this->assertTrue(count($fixture->response->docs) > 0, 'There are not 1 or more documents, cannot test');
$this->assertInstanceOf('stdClass', $fixture->response->docs[0], 'The first document is not of type stdClass');
}
public function testGetHttpStatusMessage()
{
$fixture = self::get200Response();
$this->assertEquals("OK", $fixture->getHttpStatusMessage());
}
public function testMagicGetReturnsNullForUndefinedData()
{
$fixture = self::get200Response();
$this->assertNull($fixture->doesnotexist);
}
public function testMagicIssetForDefinedProperty()
{
$fixture = self::get200Response();
$this->assertTrue(isset($fixture->responseHeader));
}
public function testMagicIssetForUndefinedProperty()
{
$fixture = self::get200Response();
$this->assertFalse(isset($fixture->doesnotexist));
}
}

View File

@ -0,0 +1,47 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Donovan Jimenez <djimenez@conduit-it.com>
*/
/**
* Apache_Solr_Service_Balancer Unit Tests
*/
class Apache_Solr_Service_BalancerTest extends Apache_Solr_ServiceAbstractTest
{
public function getFixture()
{
return new Apache_Solr_Service_Balancer();
}
}

View File

@ -0,0 +1,139 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Donovan Jimenez <djimenez@conduit-it.com>
*/
/**
* Provides base funcationality test for both Apache_Solr_Service and the
* Apache_Solr_Service_Balancer classes.
*/
abstract class Apache_Solr_ServiceAbstractTest extends PHPUnit_Framework_TestCase
{
/**
* Method that gets the appropriate instance for testing
*/
abstract public function getFixture();
/**
* @dataProvider testEscapeDataProvider
*/
public function testEscape($input, $expectedOutput)
{
$fixture = $this->getFixture();
$this->assertEquals($expectedOutput, $fixture->escape($input));
}
public function testEscapeDataProvider()
{
return array(
array(
"I should look the same",
"I should look the same"
),
array(
"(There) are: ^lots \\ && of spec!al charaters",
"\\(There\\) are\\: \\^lots \\\\ \\&& of spec\\!al charaters"
)
);
}
/**
* @dataProvider testEscapePhraseDataProvider
*/
public function testEscapePhrase($input, $expectedOutput)
{
$fixture = $this->getFixture();
$this->assertEquals($expectedOutput, $fixture->escapePhrase($input));
}
public function testEscapePhraseDataProvider()
{
return array(
array(
"I'm a simple phrase",
"I'm a simple phrase"
),
array(
"I have \"phrase\" characters",
'I have \\"phrase\\" characters'
)
);
}
/**
* @dataProvider testPhraseDataProvider
*/
public function testPhrase($input, $expectedOutput)
{
$fixture = $this->getFixture();
$this->assertEquals($expectedOutput, $fixture->phrase($input));
}
public function testPhraseDataProvider()
{
return array(
array(
"I'm a simple phrase",
'"I\'m a simple phrase"'
),
array(
"I have \"phrase\" characters",
'"I have \\"phrase\\" characters"'
)
);
}
public function testGetCreateDocumentWithDefaultConstructor()
{
$fixture = $this->getFixture();
$this->assertTrue($fixture->getCreateDocuments());
}
public function testSetCreateDocuments()
{
$fixture = $this->getFixture();
$fixture->setCreateDocuments(false);
$this->assertFalse($fixture->getCreateDocuments());
}
}

View File

@ -0,0 +1,1180 @@
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright Copyright 2007-2013 PTC Inc. (http://ptc.com)
* @license https://raw.github.com/PTCInc/solr-php-client/master/COPYING 3-Clause BSD
*
* @package Apache
* @subpackage Solr
* @author Donovan Jimenez <djimenez@conduit-it.com>
*/
/**
* Apache_Solr_Service Unit Test
*/
class Apache_Solr_ServiceTest extends Apache_Solr_ServiceAbstractTest
{
public function getFixture()
{
return new Apache_Solr_Service();
}
public function getMockHttpTransportInterface()
{
return $this->getMock(
'Apache_Solr_HttpTransport_Interface',
array(
'getDefaultTimeout',
'setDefaultTimeout',
'setAuthenticationCredentials',
'performGetRequest',
'performHeadRequest',
'performPostRequest',
)
);
}
//================================================================//
// ATTEMPT TO MOVE THESE TO ServiceAbstractTest AT SOME POINT //
// Apache_Solr_Service_Balancer will need functions added //
//================================================================//
public function testGetHttpTransportWithDefaultConstructor()
{
$fixture = new Apache_Solr_Service();
$httpTransport = $fixture->getHttpTransport();
$this->assertInstanceOf('Apache_Solr_HttpTransport_Interface', $httpTransport, 'Default http transport does not implement interface');
$this->assertInstanceOf('Apache_Solr_HttpTransport_FileGetContents', $httpTransport, 'Default http transport is not URL Wrapper implementation');
}
public function testSetHttpTransport()
{
$newTransport = new Apache_Solr_HttpTransport_Curl();
$fixture = new Apache_Solr_Service();
$fixture->setHttpTransport($newTransport);
$httpTransport = $fixture->getHttpTransport();
$this->assertInstanceOf('Apache_Solr_HttpTransport_Interface', $httpTransport);
$this->assertInstanceOf('Apache_Solr_HttpTransport_Curl', $httpTransport);
$this->assertEquals($newTransport, $httpTransport);
}
public function testSetHttpTransportWithConstructor()
{
$newTransport = new Apache_Solr_HttpTransport_Curl();
$fixture = new Apache_Solr_Service('localhost', 8180, '/solr/', $newTransport);
$fixture->setHttpTransport($newTransport);
$httpTransport = $fixture->getHttpTransport();
$this->assertInstanceOf('Apache_Solr_HttpTransport_Interface', $httpTransport);
$this->assertInstanceOf('Apache_Solr_HttpTransport_Curl', $httpTransport);
$this->assertEquals($newTransport, $httpTransport);
}
public function testGetCollapseSingleValueArraysWithDefaultConstructor()
{
$fixture = $this->getFixture();
$this->assertTrue($fixture->getCollapseSingleValueArrays());
}
public function testSetCollapseSingleValueArrays()
{
$fixture = $this->getFixture();
$fixture->setCollapseSingleValueArrays(false);
$this->assertFalse($fixture->getCollapseSingleValueArrays());
}
public function testGetNamedListTreatmetnWithDefaultConstructor()
{
$fixture = $this->getFixture();
$this->assertEquals(Apache_Solr_Service::NAMED_LIST_MAP, $fixture->getNamedListTreatment());
}
public function testSetNamedListTreatment()
{
$fixture = $this->getFixture();
$fixture->setNamedListTreatment(Apache_Solr_Service::NAMED_LIST_FLAT);
$this->assertEquals(Apache_Solr_Service::NAMED_LIST_FLAT, $fixture->getNamedListTreatment());
$fixture->setNamedListTreatment(Apache_Solr_Service::NAMED_LIST_MAP);
$this->assertEquals(Apache_Solr_Service::NAMED_LIST_MAP, $fixture->getNamedListTreatment());
}
/**
* @expectedException Apache_Solr_InvalidArgumentException
*/
public function testSetNamedListTreatmentInvalidArgumentException()
{
$fixture = $this->getFixture();
$fixture->setNamedListTreatment("broken");
}
//================================================================//
// END SECTION OF CODE THAT SHOULD BE MOVED //
// Apache_Solr_Service_Balancer will need functions added //
//================================================================//
public function testConstructorDefaultArguments()
{
$fixture = new Apache_Solr_Service();
$this->assertInstanceOf('Apache_Solr_Service', $fixture);
}
public function testGetHostWithDefaultConstructor()
{
$fixture = new Apache_Solr_Service();
$host = $fixture->getHost();
$this->assertEquals("localhost", $host);
}
public function testSetHost()
{
$newHost = "example.com";
$fixture = new Apache_Solr_Service();
$fixture->setHost($newHost);
$host = $fixture->getHost();
$this->assertEquals($newHost, $host);
}
/**
* @expectedException Apache_Solr_InvalidArgumentException
*/
public function testSetEmptyHost()
{
$fixture = new Apache_Solr_Service();
// should throw an invalid argument exception
$fixture->setHost("");
}
public function testSetHostWithConstructor()
{
$newHost = "example.com";
$fixture = new Apache_Solr_Service($newHost);
$host = $fixture->getHost();
$this->assertEquals($newHost, $host);
}
public function testGetPortWithDefaultConstructor()
{
$fixture = new Apache_Solr_Service();
$port = $fixture->getPort();
$this->assertEquals(8180, $port);
}
public function testSetPort()
{
$newPort = 12345;
$fixture = new Apache_Solr_Service();
$fixture->setPort($newPort);
$port = $fixture->getPort();
$this->assertEquals($newPort, $port);
}
/**
* @expectedException Apache_Solr_InvalidArgumentException
*/
public function testSetPortWithInvalidArgument()
{
$fixture = new Apache_Solr_Service();
$fixture->setPort("broken");
}
public function testSetPortWithConstructor()
{
$newPort = 12345;
$fixture = new Apache_Solr_Service('locahost', $newPort);
$port = $fixture->getPort();
$this->assertEquals($newPort, $port);
}
public function testGetPathWithDefaultConstructor()
{
$fixture = new Apache_Solr_Service();
$path = $fixture->getPath();
$this->assertEquals("/solr/", $path);
}
public function testSetPath()
{
$newPath = "/new/path/";
$fixture = new Apache_Solr_Service();
$fixture->setPath($newPath);
$path = $fixture->getPath();
$this->assertEquals($path, $newPath);
}
public function testSetPathWillAddContainingSlashes()
{
$newPath = "new/path";
$containedPath = "/{$newPath}/";
$fixture = new Apache_Solr_Service();
$fixture->setPath($newPath);
$path = $fixture->getPath();
$this->assertEquals($containedPath, $path, 'setPath did not ensure propertly wrapped with slashes');
}
public function testSetPathWithConstructor()
{
$newPath = "/new/path/";
$fixture = new Apache_Solr_Service('localhost', 8180, $newPath);
$path = $fixture->getPath();
$this->assertEquals($newPath, $path);
}
public function testGetDefaultTimeoutCallsThroughToTransport()
{
$fixture = new Apache_Solr_Service();
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call
$mockTransport->expects($this->once())->method('getDefaultTimeout');
$fixture->setHttpTransport($mockTransport);
$fixture->getDefaultTimeout();
}
public function testSetDefaultTimeoutCallsThroughToTransport()
{
$timeout = 12345;
$fixture = new Apache_Solr_Service();
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call
$mockTransport->expects($this->once())->method('setDefaultTimeout')->with($this->equalTo($timeout));
$fixture->setHttpTransport($mockTransport);
$fixture->setDefaultTimeout($timeout);
}
public function testSetAuthenticationCredentialsCallsThroughToTransport()
{
$username = "user";
$password = "password";
$fixture = new Apache_Solr_Service();
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call
$mockTransport->expects($this->once())->method('setAuthenticationCredentials')->with($this->equalTo($username), $this->equalTo($password));
$fixture->setHttpTransport($mockTransport);
$fixture->setAuthenticationCredentials($username, $password);
}
public function testPing()
{
$expectedUrl = "http://localhost:8180/solr/admin/ping";
$expectedTimeout = 2;
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performHeadRequest')
->with($this->equalTo($expectedUrl), $this->equalTo($expectedTimeout))
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
// call ping
$fixture = new Apache_Solr_service();
$fixture->setHttpTransport($mockTransport);
$time = $fixture->ping();
$this->assertGreaterThan(0, $time);
}
public function testPingReturnsFalse()
{
$expectedUrl = "http://localhost:8180/solr/admin/ping";
$expectedTimeout = 2;
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performHeadRequest')
->with($this->equalTo($expectedUrl), $this->equalTo($expectedTimeout))
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get0Response()));
// call ping
$fixture = new Apache_Solr_service();
$fixture->setHttpTransport($mockTransport);
$this->assertFalse($fixture->ping());
}
public function testSystem()
{
$expectedUrl = "http://localhost:8180/solr/admin/system?wt=json";
$expectedTimeout = false;
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performGetRequest')
->with($this->equalTo($expectedUrl), $this->equalTo($expectedTimeout))
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
// call system
$fixture = new Apache_Solr_service();
$fixture->setHttpTransport($mockTransport);
$fixture->system();
}
/**
* @expectedException Apache_Solr_HttpTransportException
*/
public function testSystem404()
{
$expectedUrl = "http://localhost:8180/solr/admin/system?wt=json";
$expectedTimeout = false;
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performGetRequest')
->with($this->equalTo($expectedUrl), $this->equalTo($expectedTimeout))
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get404Response()));
// call system
$fixture = new Apache_Solr_service();
$fixture->setHttpTransport($mockTransport);
$fixture->system();
}
public function testThreads()
{
$expectedUrl = "http://localhost:8180/solr/admin/threads?wt=json";
$expectedTimeout = false;
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performGetRequest')
->with($this->equalTo($expectedUrl), $this->equalTo($expectedTimeout))
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
// call threads
$fixture = new Apache_Solr_service();
$fixture->setHttpTransport($mockTransport);
$fixture->threads();
}
/**
* @expectedException Apache_Solr_HttpTransportException
*/
public function testThreads404()
{
$expectedUrl = "http://localhost:8180/solr/admin/threads?wt=json";
$expectedTimeout = false;
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performGetRequest')
->with($this->equalTo($expectedUrl), $this->equalTo($expectedTimeout))
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get404Response()));
// call threads
$fixture = new Apache_Solr_service();
$fixture->setHttpTransport($mockTransport);
$fixture->threads();
}
public function testAdd()
{
$postData = "does not have to be valid";
$expectedUrl = "http://localhost:8180/solr/update?wt=json";
$expectedTimeout = false;
$expectedPostData = $postData;
$expectedContentType = "text/xml; charset=UTF-8"; // default for _sendRawPost
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performPostRequest')
->with($this->equalTo($expectedUrl), $this->equalTo($postData), $this->equalTo($expectedContentType), $this->equalTo($expectedTimeout))
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
// call add
$fixture = new Apache_Solr_service();
$fixture->setHttpTransport($mockTransport);
$fixture->add($postData);
}
/**
* @expectedException Apache_Solr_HttpTransportException
*/
public function testAdd400()
{
$postData = "does not have to be valid";
$expectedUrl = "http://localhost:8180/solr/update?wt=json";
$expectedTimeout = false;
$expectedPostData = $postData;
$expectedContentType = "text/xml; charset=UTF-8"; // default for _sendRawPost
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performPostRequest')
->with($this->equalTo($expectedUrl), $this->equalTo($postData), $this->equalTo($expectedContentType), $this->equalTo($expectedTimeout))
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get400Response()));
// call add
$fixture = new Apache_Solr_service();
$fixture->setHttpTransport($mockTransport);
$fixture->add($postData);
}
public function testAddDocument()
{
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performPostRequest')
->with(
// url
$this->equalTo('http://localhost:8180/solr/update?wt=json'),
// raw post
$this->equalTo('<add allowDups="false" overwritePending="true" overwriteCommitted="true"><doc></doc></add>'),
// content type
$this->equalTo('text/xml; charset=UTF-8'),
// timeout
$this->equalTo(false)
)
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
$fixture = new Apache_Solr_service();
$fixture->setHttpTransport($mockTransport);
$document = new Apache_Solr_Document();
$fixture->addDocument($document);
}
public function testAddDocumentWithNonDefaultParameters()
{
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performPostRequest')
->with(
// url
$this->equalTo('http://localhost:8180/solr/update?wt=json'),
// raw post
$this->equalTo('<add allowDups="true" overwritePending="false" overwriteCommitted="false" commitWithin="3600"><doc></doc></add>'),
// content type
$this->equalTo('text/xml; charset=UTF-8'),
// timeout
$this->equalTo(false)
)
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
$fixture = new Apache_Solr_service();
$fixture->setHttpTransport($mockTransport);
$document = new Apache_Solr_Document();
$fixture->addDocument($document, true, false, false, 3600);
}
public function testAddDocumentWithFields()
{
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performPostRequest')
->with(
// url
$this->equalTo('http://localhost:8180/solr/update?wt=json'),
// raw post
$this->equalTo('<add allowDups="false" overwritePending="true" overwriteCommitted="true"><doc><field name="guid">global unique id</field><field name="field">value</field><field name="multivalue">value 1</field><field name="multivalue">value 2</field></doc></add>'),
// content type
$this->equalTo('text/xml; charset=UTF-8'),
// timeout
$this->equalTo(false)
)
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
$fixture = new Apache_Solr_service();
$fixture->setHttpTransport($mockTransport);
$document = new Apache_Solr_Document();
$document->guid = "global unique id";
$document->field = "value";
$document->multivalue = array("value 1", "value 2");
$fixture->addDocument($document);
}
public function testAddDocumentWithFieldBoost()
{
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performPostRequest')
->with(
// url
$this->equalTo('http://localhost:8180/solr/update?wt=json'),
// raw post
$this->equalTo('<add allowDups="false" overwritePending="true" overwriteCommitted="true"><doc><field name="guid">global unique id</field><field name="field" boost="2">value</field><field name="multivalue" boost="3">value 1</field><field name="multivalue">value 2</field></doc></add>'),
// content type
$this->equalTo('text/xml; charset=UTF-8'),
// timeout
$this->equalTo(false)
)
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
$fixture = new Apache_Solr_service();
$fixture->setHttpTransport($mockTransport);
$document = new Apache_Solr_Document();
$document->guid = "global unique id";
$document->field = "value";
$document->setFieldBoost('field', 2);
$document->multivalue = array("value 1", "value 2");
$document->setFieldBoost('multivalue', 3);
$fixture->addDocument($document);
}
public function testAddDocumentWithDocumentBoost()
{
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performPostRequest')
->with(
// url
$this->equalTo('http://localhost:8180/solr/update?wt=json'),
// raw post
$this->equalTo('<add allowDups="false" overwritePending="true" overwriteCommitted="true"><doc boost="2"><field name="guid">global unique id</field><field name="field">value</field></doc></add>'),
// content type
$this->equalTo('text/xml; charset=UTF-8'),
// timeout
$this->equalTo(false)
)
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
$fixture = new Apache_Solr_service();
$fixture->setHttpTransport($mockTransport);
$document = new Apache_Solr_Document();
$document->setBoost(2);
$document->guid = "global unique id";
$document->field = "value";
$fixture->addDocument($document);
}
public function testAddDocuments()
{
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performPostRequest')
->with(
// url
$this->equalTo('http://localhost:8180/solr/update?wt=json'),
// raw post
$this->equalTo('<add allowDups="false" overwritePending="true" overwriteCommitted="true"><doc></doc><doc></doc></add>'),
// content type
$this->equalTo('text/xml; charset=UTF-8'),
// timeout
$this->equalTo(false)
)
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
$fixture = new Apache_Solr_service();
$fixture->setHttpTransport($mockTransport);
$documents = array(
new Apache_Solr_Document(),
new Apache_Solr_Document()
);
$fixture->addDocuments($documents);
}
public function testAddDocumentsWithNonDefaultParameters()
{
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performPostRequest')
->with(
// url
$this->equalTo('http://localhost:8180/solr/update?wt=json'),
// raw post
$this->equalTo('<add allowDups="true" overwritePending="false" overwriteCommitted="false" commitWithin="3600"><doc></doc><doc></doc></add>'),
// content type
$this->equalTo('text/xml; charset=UTF-8'),
// timeout
$this->equalTo(false)
)
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
$fixture = new Apache_Solr_service();
$fixture->setHttpTransport($mockTransport);
$documents = array(
new Apache_Solr_Document(),
new Apache_Solr_Document()
);
$fixture->addDocuments($documents, true, false, false, 3600);
}
public function testCommit()
{
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performPostRequest')
->with(
// url
$this->equalTo('http://localhost:8180/solr/update?wt=json'),
// raw post
$this->equalTo('<commit expungeDeletes="false" waitFlush="true" waitSearcher="true" />'),
// content type
$this->equalTo('text/xml; charset=UTF-8'),
// timeout
$this->equalTo(3600)
)
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
$fixture = new Apache_Solr_Service();
$fixture->setHttpTransport($mockTransport);
$fixture->commit();
}
public function testCommitWithNonDefaultParameters()
{
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performPostRequest')
->with(
// url
$this->equalTo('http://localhost:8180/solr/update?wt=json'),
// raw post
$this->equalTo('<commit expungeDeletes="true" waitFlush="false" waitSearcher="false" />'),
// content type
$this->equalTo('text/xml; charset=UTF-8'),
// timeout
$this->equalTo(7200)
)
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
$fixture = new Apache_Solr_Service();
$fixture->setHttpTransport($mockTransport);
$fixture->commit(true, false, false, 7200);
}
public function testDelete()
{
$postData = "does not have to be valid";
$expectedUrl = "http://localhost:8180/solr/update?wt=json";
$expectedTimeout = 3600; // default for delete
$expectedPostData = $postData;
$expectedContentType = "text/xml; charset=UTF-8"; // default for _sendRawPost
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performPostRequest')
->with($this->equalTo($expectedUrl), $this->equalTo($postData), $this->equalTo($expectedContentType), $this->equalTo($expectedTimeout))
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
// call add
$fixture = new Apache_Solr_service();
$fixture->setHttpTransport($mockTransport);
$fixture->delete($postData);
}
public function testDeleteById()
{
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performPostRequest')
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
$fixture = new Apache_Solr_Service();
$fixture->setHttpTransport($mockTransport);
$fixture->deleteById("does not exist");
}
public function testDeleteByMultipleIds()
{
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performPostRequest')
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
$fixture = new Apache_Solr_Service();
$fixture->setHttpTransport($mockTransport);
$fixture->deleteByMultipleIds(array(1, 2, 3));
}
public function testDeleteByQuery()
{
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performPostRequest')
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
$fixture = new Apache_Solr_Service();
$fixture->setHttpTransport($mockTransport);
$fixture->deleteByQuery("*:*");
}
public function testExtracts()
{
$extractFile = __FILE__;
$expectedUrl = "http://localhost:8180/solr/update/extract?resource.name=ServiceTest.php&wt=json&json.nl=map";
$expectedPostData = file_get_contents($extractFile);
$expectedContentType = 'application/octet-stream'; // default for extract
$expectedTimeout = false;
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performPostRequest')
->with($this->equalTo($expectedUrl), $this->equalTo($expectedPostData), $this->equalTo($expectedContentType), $this->equalTo($expectedTimeout))
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
$fixture = new Apache_Solr_Service();
$fixture->setHttpTransport($mockTransport);
$fixture->extract($extractFile);
}
/**
* @expectedException Apache_Solr_InvalidArgumentException
*/
public function testExtractWithInvalidParams()
{
$extractFile = __FILE__;
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
$fixture = new Apache_Solr_Service();
$fixture->setHttpTransport($mockTransport);
$fixture->extract($extractFile, "invalid");
}
/**
* @expectedException Apache_Solr_InvalidArgumentException
*/
public function testExtractFromStringWithInvalidParams()
{
$extractFileData = "does not matter what it is";
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
$fixture = new Apache_Solr_Service();
$fixture->setHttpTransport($mockTransport);
$fixture->extractFromString($extractFileData, "invalid");
}
public function testExtractsWithNullParams()
{
$extractFile = __FILE__;
$expectedUrl = "http://localhost:8180/solr/update/extract?resource.name=ServiceTest.php&wt=json&json.nl=map";
$expectedPostData = file_get_contents($extractFile);
$expectedContentType = 'application/octet-stream'; // default for extract
$expectedTimeout = false;
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performPostRequest')
->with($this->equalTo($expectedUrl), $this->equalTo($expectedPostData), $this->equalTo($expectedContentType), $this->equalTo($expectedTimeout))
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
$fixture = new Apache_Solr_Service();
$fixture->setHttpTransport($mockTransport);
$fixture->extract($extractFile, null);
}
/**
* @expectedException Apache_Solr_InvalidArgumentException
*/
public function testExtractWithEmptyFile()
{
$extractFile = "iDontExist.txt";
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
$fixture = new Apache_Solr_Service();
$fixture->setHttpTransport($mockTransport);
$fixture->extract($extractFile);
}
public function testExtractsWithDocument()
{
$extractFile = __FILE__;
$expectedUrl = "http://localhost:8180/solr/update/extract?resource.name=ServiceTest.php&wt=json&json.nl=map&boost.field=2&literal.field=literal+value";
$expectedPostData = file_get_contents($extractFile);
$expectedContentType = 'application/octet-stream'; // default for extract
$expectedTimeout = false;
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performPostRequest')
->with($this->equalTo($expectedUrl), $this->equalTo($expectedPostData), $this->equalTo($expectedContentType), $this->equalTo($expectedTimeout))
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
$fixture = new Apache_Solr_Service();
$fixture->setHttpTransport($mockTransport);
$literals = new Apache_Solr_Document();
$literals->field = "literal value";
$literals->setFieldBoost('field', 2);
$fixture->extract($extractFile, null, $literals);
}
public function testExtractWithUrlDefers()
{
$extractUrl = "http://example.com";
$expectedUrl = "http://localhost:8180/solr/update/extract?resource.name=http%3A%2F%2Fexample.com&wt=json&json.nl=map";
$expectedPostData = Apache_Solr_HttpTransport_ResponseTest::BODY_200;
$expectedContentType = 'application/octet-stream'; // default for extract
$expectedTimeout = false;
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performGetRequest')
->with(
$this->equalTo($extractUrl)
)
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
$mockTransport->expects($this->once())
->method('performPostRequest')
->with(
$this->equalTo($expectedUrl),
$this->equalTo($expectedPostData),
$this->equalTo($expectedContentType),
$this->equalTo($expectedTimeout)
)
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
$fixture = new Apache_Solr_Service();
$fixture->setHttpTransport($mockTransport);
$fixture->extract($extractUrl);
}
public function testExtractFromUrl()
{
$extractUrl = "http://example.com";
$expectedUrl = "http://localhost:8180/solr/update/extract?resource.name=http%3A%2F%2Fexample.com&wt=json&json.nl=map";
$expectedPostData = Apache_Solr_HttpTransport_ResponseTest::BODY_200;
$expectedContentType = 'application/octet-stream'; // default for extract
$expectedTimeout = false;
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performGetRequest')
->with(
$this->equalTo($extractUrl)
)
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
$mockTransport->expects($this->once())
->method('performPostRequest')
->with(
$this->equalTo($expectedUrl),
$this->equalTo($expectedPostData),
$this->equalTo($expectedContentType),
$this->equalTo($expectedTimeout)
)
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
$fixture = new Apache_Solr_Service();
$fixture->setHttpTransport($mockTransport);
$fixture->extractFromUrl($extractUrl);
}
/**
* @expectedException Apache_Solr_InvalidArgumentException
*/
public function testExtractFromUrlWithInvalidParams()
{
$extractUrl = "http://example.com";
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
$fixture = new Apache_Solr_Service();
$fixture->setHttpTransport($mockTransport);
$fixture->extractFromUrl($extractUrl, "invalid");
}
public function testOptimize()
{
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performPostRequest')
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
$fixture = new Apache_Solr_Service();
$fixture->setHttpTransport($mockTransport);
$fixture->optimize();
}
public function testSearch()
{
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performGetRequest')
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
$fixture = new Apache_Solr_service();
$fixture->setHttpTransport($mockTransport);
$fixture->search("solr");
}
/**
* @expectedException Apache_Solr_InvalidArgumentException
*/
public function testSearchWithInvalidParams()
{
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
$fixture = new Apache_Solr_service();
$fixture->setHttpTransport($mockTransport);
$fixture->search("solr", 0, 10, "invalid");
$this->fail("Should have through InvalidArgumentException");
}
public function testSearchWithEmptyParams()
{
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performGetRequest')
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
$fixture = new Apache_Solr_service();
$fixture->setHttpTransport($mockTransport);
$fixture->search("solr", 0, 10, null);
}
public function testSearchWithPostMethod()
{
// set a mock transport
$mockTransport = $this->getMockHttpTransportInterface();
// setup expected call and response
$mockTransport->expects($this->once())
->method('performPostRequest')
->will($this->returnValue(Apache_Solr_HttpTransport_ResponseTest::get200Response()));
$fixture = new Apache_Solr_service();
$fixture->setHttpTransport($mockTransport);
$fixture->search("solr", 0, 10, array(), Apache_Solr_Service::METHOD_POST);
}
/**
* @expectedException Apache_Solr_InvalidArgumentException
*/
public function testSearchWithInvalidMethod()
{
$fixture = new Apache_Solr_service();
$fixture->search("solr", 0, 10, array(), "INVALID METHOD");
}
}

20
thirdparty/solr-php-client/tests/README vendored Normal file
View File

@ -0,0 +1,20 @@
Use the run.php script included in this directory to run all unit tests for the
Solr PHP Client library. Your system will require phpunit PEAR package - which
you can get install instructions for at:
http://www.phpunit.de/
To generate the code coverage report, you will also need the XDebug pecl package
installed, typically this can be done with a simple:
pecl install xdebug
If you need more information on installation, then please see the official website:
http://www.xdebug.org
The scripts, configuration, and test files in this directory have been confirmed to
work with the following versions:
phpunit: 3.3.16
xdebug: 2.0.4

View File

@ -0,0 +1,28 @@
<?php
// set error reporting high
error_reporting(E_ALL | E_STRICT);
// make sure we see them
ini_set('display_errors', 'On');
// make sure current directory and class directories are on include path
// this is necessary for auto load to work
set_include_path(
// distribution files (where the zip / tgz is unpacked)
dirname(dirname(__FILE__)) . PATH_SEPARATOR .
// test file directory "tests"
dirname(__FILE__) . PATH_SEPARATOR .
// current include path (for PHPUnit, etc.)
get_include_path()
);
// set up an autoload for Zend / Pear style class loading
spl_autoload_register(
function($class)
{
include(str_replace("_", DIRECTORY_SEPARATOR, $class) . ".php");
}
);

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<phpunit bootstrap="phpunit.bootstrap.inc" colors="true">
<logging>
<log type="coverage-html" target="coverage-report" charset="UTF-8"/>
<!--<log type="testdox-text" target="testdox.txt" charset="UTF-8"/>-->
</logging>
<filter>
<whitelist>
<directory suffix=".php">../Apache</directory>
<exclude>
<file>./run.php</file>
</exclude>
</whitelist>
</filter>
</phpunit>

42
thirdparty/solr-php-client/tests/run.php vendored Executable file
View File

@ -0,0 +1,42 @@
#! /usr/bin/php
<?php
/**
* Copyright (c) 2007-2013, PTC Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of PTC Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
// make sure the working directory is correct (parent directory)
// phpunit will use it to include our configuration files and find
// the following specified test suite
chdir(dirname(__FILE__));
// run phpunit - will automatically use ./phpunit.xml for configuration
// that configuration file points to a bootstrap that will include our test suite
passthru("phpunit .");
// extra newline so our next prompt isn't stuck appended to the output
echo "\n";