Commit 224cb529 authored by Bas de Nooijer's avatar Bas de Nooijer

Merge branch 'release/3.1'

parents 10c455fe d733309d
......@@ -17,10 +17,5 @@
},
"autoload": {
"psr-0": { "Solarium": "library/" }
},
"extra": {
"branch-alias": {
"dev-develop": "3.0-dev"
}
}
}
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
// get the facetset component
$facetSet = $query->getFacetSet();
// create two facet pivot instances
$facet = $facetSet->createFacetPivot('cat-popularity-instock');
$facet->addFields('cat,popularity,inStock');
$facet->setMinCount(0);
$facet = $facetSet->createFacetPivot('popularity-cat');
$facet->addFields('popularity,cat');
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// display facet results
$facetResult = $resultset->getFacetSet()->getFacet('cat-popularity-instock');
echo '<h3>cat &raquo; popularity &raquo; instock</h3>';
foreach($facetResult as $pivot){
display_pivot_facet($pivot);
}
$facetResult = $resultset->getFacetSet()->getFacet('popularity-cat');
echo '<h3>popularity &raquo; cat</h3>';
foreach($facetResult as $pivot){
display_pivot_facet($pivot);
}
htmlFooter();
/**
* Recursively render pivot facets
*
* @param $pivot
*/
function display_pivot_facet($pivot)
{
echo '<ul>';
echo '<li>Field: '.$pivot->getField().'</li>';
echo '<li>Value: '.$pivot->getValue().'</li>';
echo '<li>Count: '.$pivot->getCount().'</li>';
foreach ($pivot->getPivot() as $nextPivot) {
display_pivot_facet($nextPivot);
}
echo '</ul>';
}
\ No newline at end of file
......@@ -12,7 +12,8 @@ $query->setRows(0);
// add spellcheck settings
$spellcheck = $query->getSpellcheck();
$spellcheck->setQuery('delll ultrashar');
$spellcheck->setQuery('tes');
$spellcheck->setCount(10);
$spellcheck->setBuild(true);
$spellcheck->setCollate(true);
$spellcheck->setExtendedResults(true);
......@@ -35,8 +36,12 @@ foreach($spellcheckResult as $suggestion) {
echo 'StartOffset: '.$suggestion->getStartOffset().'<br/>';
echo 'EndOffset: '.$suggestion->getEndOffset().'<br/>';
echo 'OriginalFrequency: '.$suggestion->getOriginalFrequency().'<br/>';
echo 'Frequency: '.$suggestion->getFrequency().'<br/>';
echo 'Word: '.$suggestion->getWord().'<br/>';
foreach ($suggestion->getWords() as $word) {
echo '-----<br/>';
echo 'Frequency: '.$word['freq'].'<br/>';
echo 'Word: '.$word['word'].'<br/>';
}
echo '<hr/>';
}
......
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get an update query instance
$update = $client->createUpdate();
// create a new document
$id = time();
$doc1 = $update->createDocument();
$doc1->id = $id;
$doc1->name = 'realtime-get-test-'.date('Y-m-d H:i:s');
// set a very long commitWithin time and add it to solr
$update->addDocument($doc1, null, 1000000);
$client->update($update);
// try to get the document using a normal select, this should return 0 results
$query = $client->createSelect();
$query->setQuery('id:%1%', array($id));
$resultset = $client->select($query);
echo 'NumFound with standard select: '.$resultset->getNumFound().'<br/>';
// now with realtime get, this should return 1 result
$query = $client->createRealtimeGet();
$query->addId($id);
$result = $client->realtimeGet($query);
echo 'NumFound with realtime get: '.$result->getNumFound().'<br/>';
// Display the document
echo '<hr/><table>';
foreach($result->getDocument() AS $field => $value)
{
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
htmlFooter();
\ No newline at end of file
......@@ -41,6 +41,7 @@
<li><a href="2.1.5.1.2-facet-query.php">2.1.5.1.2 Facet query</a></li>
<li><a href="2.1.5.1.3-facet-multiquery.php">2.1.5.1.3 Facet multiquery</a></li>
<li><a href="2.1.5.1.4-facet-range.php">2.1.5.1.4 Facet range</a></li>
<li><a href="2.1.5.1.5-facet-pivot.php">2.1.5.1.5 Facet pivot</a></li>
</ul>
<li><a href="2.1.5.2-morelikethis.php">2.1.5.2 MoreLikeThis</a></li>
<li><a href="2.1.5.3-highlighting.php">2.1.5.3 Highlighting</a></li>
......@@ -86,6 +87,7 @@
<li><a href="2.6-suggester-query.php">2.6 Suggester query</a></li>
<li><a href="2.7-extract-query.php">2.7 Extract query</a></li>
<li><a href="2.8-realtime-get-query.php">2.8 Realtime get query</a></li>
</ul>
<li>4. Usage modes</li>
......
......@@ -120,8 +120,8 @@ class Curl extends Configurable implements AdapterInterface
$data = '';
}
$this->check($data, $headers, $handle);
curl_close($handle);
$this->check($data, $headers);
return new Response($data, $headers);
// @codeCoverageIgnoreEnd
......@@ -156,7 +156,10 @@ class Curl extends Configurable implements AdapterInterface
$options['headers']['Content-Type'] = 'text/xml; charset=utf-8';
}
$authData = $request->getAuthentication();
// Try endpoint authentication first, fallback to request for backwards compatibility
$authData = $endpoint->getAuthentication();
if(empty($authData['username'])) $authData = $request->getAuthentication();
if ( !empty($authData['username']) && !empty($authData['password'])) {
curl_setopt($handler, CURLOPT_USERPWD, $authData['username']. ':' . $authData['password'] );
curl_setopt($handler, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
......@@ -219,14 +222,15 @@ class Curl extends Configurable implements AdapterInterface
* @throws HttpException
* @param string $data
* @param array $headers
* @param Curl handle $handle
* @return void
*/
public function check($data, $headers)
public function check($data, $headers, $handle)
{
// if there is no data and there are no headers it's a total failure,
// a connection to the host was impossible.
if (empty($data) && count($headers) == 0) {
throw new HttpException("HTTP request failed");
throw new HttpException('HTTP request failed, '.curl_error($handle));
}
}
}
......@@ -127,7 +127,10 @@ class Http extends Configurable implements AdapterInterface
}
}
$authData = $request->getAuthentication();
// Try endpoint authentication first, fallback to request for backwards compatibility
$authData = $endpoint->getAuthentication();
if(empty($authData['username'])) $authData = $request->getAuthentication();
if ( !empty($authData['username']) && !empty($authData['password'])) {
$request->addHeader('Authorization: Basic ' . base64_encode($authData['username']. ':' . $authData['password'] ));
}
......
......@@ -150,7 +150,10 @@ class PeclHttp extends Configurable implements AdapterInterface
}
}
$authData = $request->getAuthentication();
// Try endpoint authentication first, fallback to request for backwards compatibility
$authData = $endpoint->getAuthentication();
if(empty($authData['username'])) $authData = $request->getAuthentication();
if ( !empty($authData['username']) && !empty($authData['password'])) {
$headers['Authorization'] = 'Basic ' . base64_encode($authData['username']. ':' . $authData['password'] );
}
......
......@@ -122,6 +122,11 @@ class Client extends Configurable
*/
const QUERY_EXTRACT = 'extract';
/**
* Querytype get
*/
const QUERY_REALTIME_GET = 'get';
/**
* Default options
*
......@@ -149,6 +154,7 @@ class Client extends Configurable
self::QUERY_TERMS => 'Solarium\QueryType\Terms\Query',
self::QUERY_SUGGESTER => 'Solarium\QueryType\Suggester\Query',
self::QUERY_EXTRACT => 'Solarium\QueryType\Extract\Query',
self::QUERY_REALTIME_GET => 'Solarium\QueryType\RealtimeGet\Query',
);
/**
......@@ -239,9 +245,10 @@ class Client extends Configurable
* after setting the key, by using the addEndpoint method.
*
* @param mixed $options
* @param boolean $setAsDefault
* @return Endpoint
*/
public function createEndpoint($options = null)
public function createEndpoint($options = null, $setAsDefault = false)
{
if (is_string($options)) {
$endpoint = new Endpoint;
......@@ -252,6 +259,9 @@ class Client extends Configurable
if ($endpoint->getKey() !== null) {
$this->addEndpoint($endpoint);
if ($setAsDefault == true) {
$this->setDefaultEndpoint($endpoint);
}
}
return $endpoint;
......@@ -954,6 +964,21 @@ class Client extends Configurable
return $this->execute($query, $endpoint);
}
/**
* Execute a RealtimeGet query
*
* @internal This is a convenience method that forwards the query to the
* execute method, thus allowing for an easy to use and clean API.
*
* @param \Solarium\QueryType\RealtimeGet\Query $query
* @param Endpoint|string|null
* @return \Solarium\QueryType\RealtimeGet\Result
*/
public function realtimeGet(QueryInterface $query, $endpoint = null)
{
return $this->execute($query, $endpoint);
}
/**
* Create a query instance
*
......@@ -1089,4 +1114,15 @@ class Client extends Configurable
{
return $this->createQuery(self::QUERY_EXTRACT, $options);
}
/**
* Create a RealtimeGet query instance
*
* @param mixed $options
* @return \Solarium\QueryType\RealtimeGet\Query
*/
public function createRealtimeGet($options = null)
{
return $this->createQuery(self::QUERY_REALTIME_GET, $options);
}
}
......@@ -228,4 +228,56 @@ class Endpoint extends Configurable
return $uri;
}
/**
* Set HTTP basic auth settings
*
* If one or both values are NULL authentication will be disabled
*
* @param string $username
* @param string $password
* @return self Provides fluent interface
*/
public function setAuthentication($username, $password)
{
$this->setOption('username', $username);
$this->setOption('password', $password);
return $this;
}
/**
* Get HTTP basic auth settings
*
* @return array
*/
public function getAuthentication()
{
return array(
'username' => $this->getOption('username'),
'password' => $this->getOption('password'),
);
}
/**
* Magic method enables a object to be transformed to a string
*
* Get a summary showing significant variables in the object
* note: uri resource is decoded for readability
*
* @return string
*/
public function __toString()
{
$output = __CLASS__ . '::__toString' . "\n"
. 'base uri: ' . $this->getBaseUri() . "\n"
. 'host: ' . $this->getHost() . "\n"
. 'port: ' . $this->getPort() ."\n"
. 'path: ' . $this->getPath() ."\n"
. 'core: ' . $this->getCore() . "\n"
. 'timeout: ' . $this->getTimeout() . "\n"
. 'authentication: ' . print_r($this->getAuthentication(), 1);
return $output;
}
}
......@@ -473,7 +473,7 @@ class Request extends Configurable
}
/**
* Get HTTP basis auth settings
* Get HTTP basic auth settings
*
* @return array
*/
......
......@@ -103,7 +103,7 @@ class Helper
*/
public function escapeTerm($input)
{
$pattern = '/(\+|-|&&|\|\||!|\(|\)|\{|}|\[|]|\^|"|~|\*|\?|:|\\\)/';
$pattern = '/(\+|-|&&|\|\||!|\(|\)|\{|}|\[|]|\^|"|~|\*|\?|:|\/|\\\)/';
return preg_replace($pattern, '\\\$1', $input);
}
......@@ -432,4 +432,51 @@ class Helper
return $this->qparser('join', array('from' => $from, 'to' => $to), $dereferenced, $dereferenced);
}
/**
* Render term query
*
* Useful for avoiding query parser escaping madness when drilling into facets via fq parameters, example:
* {!term f=weight}1.5
*
* This is a Solr 3.2+ feature.
*
* @see http://wiki.apache.org/solr/SolrQuerySyntax#Other_built-in_useful_query_parsers
*
* @param string $field
* @param float $weight
* @return string
*/
public function qparserTerm($field, $weight)
{
return $this->qparser('term',array('f' => $field)) . $weight;
}
/**
* Render cache control param for use in filterquery
*
* This is a Solr 3.4+ feature.
*
* @see http://wiki.apache.org/solr/CommonQueryParameters#Caching_of_filters
*
* @param boolean $useCache
* @param float|null $weight
* @return string
*/
public function cacheControl($useCache, $cost = null)
{
if($useCache === true) {
$cache = 'true';
} else {
$cache = 'false';
}
$result = '{!cache='.$cache;
if (null !== $cost) {
$result .= ' cost='.$cost;
}
$result .= '}';
return $result;
}
}
......@@ -47,6 +47,7 @@ use Solarium\Plugin\BufferedAdd\Event\PreFlush as PreFlushEvent;
use Solarium\Plugin\BufferedAdd\Event\PostFlush as PostFlushEvent;
use Solarium\Plugin\BufferedAdd\Event\PreCommit as PreCommitEvent;
use Solarium\Plugin\BufferedAdd\Event\PostCommit as PostCommitEvent;
use Solarium\Plugin\BufferedAdd\Event\AddDocument as AddDocumentEvent;
/**
* Buffered add plugin
......@@ -138,6 +139,10 @@ class BufferedAdd extends Plugin
public function addDocument($document)
{
$this->buffer[] = $document;
$event = new AddDocumentEvent($document);
$this->client->getEventDispatcher()->dispatch(Events::ADD_DOCUMENT, $event);
if (count($this->buffer) == $this->options['buffersize']) {
$this->flush();
}
......@@ -206,7 +211,7 @@ class BufferedAdd extends Plugin
$result = $this->client->update($this->updateQuery);
$this->clear();
$event = new PostFlushEvent($this->buffer);
$event = new PostFlushEvent($result);
$this->client->getEventDispatcher()->dispatch(Events::POST_FLUSH, $event);
return $result;
......@@ -233,7 +238,7 @@ class BufferedAdd extends Plugin
$result = $this->client->update($this->updateQuery);
$this->clear();
$event = new PostCommitEvent($this->buffer);
$event = new PostCommitEvent($result);
$this->client->getEventDispatcher()->dispatch(Events::POST_COMMIT, $event);
return $result;
......
<?php
/**
* Copyright 2011 Bas de Nooijer. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this listof conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 HOLDER 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.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the copyright holder.
*
* @copyright Copyright 2011 Bas de Nooijer <solarium@raspberry.nl>
* @license http://github.com/basdenooijer/solarium/raw/master/COPYING
* @link http://www.solarium-project.org/
*/
/**
* @namespace
*/
namespace Solarium\Plugin\BufferedAdd\Event;
use Symfony\Component\EventDispatcher\Event;
use Solarium\QueryType\Update\Result;
use Solarium\QueryType\Select\Result\DocumentInterface;
/**
* AddDocument event, see Events for details
*/
class AddDocument extends Event
{
/**
* @var DocumentInterface
*/
protected $document;
/**
* Event constructor
*
* @param DocumentInterface $document
*/
public function __construct($document)
{
$this->document = $document;
}
/**
* Get the result for this event
*
* @return DocumentInterface
*/
public function getDocument()
{
return $this->document;
}
}
......@@ -79,4 +79,13 @@ class Events
* @var string
*/
const POST_COMMIT = 'solarium.bufferedAdd.postCommit';
/**
* This event is called when a new document is added
*
* The event listener receives the Document
*
* @var string
*/
const ADD_DOCUMENT = 'solarium.bufferedAdd.addDocument';
}
......@@ -45,7 +45,7 @@ namespace Solarium\QueryType\Extract;
use Solarium\Core\Query\Query as BaseQuery;
use Solarium\Core\Client\Client;
use Solarium\QueryType\Update\ResponseParser as UpdateResponseParser;
use Solarium\QueryType\Update\Query\Document;
use Solarium\QueryType\Update\Query\Document\Document;
/**
* Extract query
......@@ -69,7 +69,7 @@ class Query extends BaseQuery
protected $options = array(
'handler' => 'update/extract',
'resultclass' => 'Solarium\QueryType\Extract\Result',
'documentclass' => 'Solarium\QueryType\Update\Query\Document',
'documentclass' => 'Solarium\QueryType\Update\Query\Document\Document',
'omitheader' => true,
);
......
<?php
/**
* Copyright 2011 Bas de Nooijer. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this listof conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 HOLDER 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.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the copyright holder.
*
* @copyright Copyright 2011 Bas de Nooijer <solarium@raspberry.nl>
* @license http://github.com/basdenooijer/solarium/raw/master/COPYING
* @link http://www.solarium-project.org/
*/
/**
* @namespace
*/
namespace Solarium\QueryType\RealtimeGet;
use Solarium\Core\Query\Query as BaseQuery;
use Solarium\Core\Client\Client;
use Solarium\QueryType\RealtimeGet\RequestBuilder as RequestBuilder;
/**
* Get query
*
* Realtime Get query for one or multiple document IDs
*
* @see http://wiki.apache.org/solr/RealTimeGet
*/
class Query extends BaseQuery
{
/**
* Default options
*
* @var array
*/
protected $options = array(
'resultclass' => 'Solarium\QueryType\RealtimeGet\Result',
'documentclass' => 'Solarium\QueryType\Select\Result\Document',
'handler' => 'get',
'omitheader' => true,
);
/**
* Document IDs
*
* @var array
*/
protected $ids = array();
/**
* Get type for this query
*
* @return string
*/
public function getType()
{
return Client::QUERY_REALTIME_GET;
}
/**
* Get a requestbuilder for this query
*
* @return RequestBuilder
*/
public function getRequestBuilder()
{
return new RequestBuilder;
}
/**
* The ping query has no response parser so we return a null value
*
* @return null;
*/
public function getResponseParser()
{
return new \Solarium\QueryType\Select\ResponseParser\ResponseParser;
}
/**
* Add an id
*
* @param string $id
* @return self Provides fluent interface
*/
public function addId($id)
{
$this->ids[$id] = true;
return $this;
}
/**
* Add multiple ids
*
* @param string|array $ids can be an array or string with comma separated ids
*
* @return self Provides fluent interface
*/
public function addIds($ids)
{
if (is_string($ids)) {
$ids = explode(',', $ids);
$ids = array_map('trim', $ids);
}
foreach ($ids as $id) {
$this->addId($id);
}
return $this;
}
/**
* Remove an id
*
* @param string $id
* @return self Provides fluent interface
*/
public function removeId($id)
{
if (isset($this->ids[$id])) {
unset($this->ids[$id]);
}
return $this;
}
/**
* Remove all IDs
*
* @return self Provides fluent interface
*/
public function clearIds()
{
$this->ids = array();
return $this;
}
/**
* Get the list of ids
*
* @return array
*/
public function getIds()
{
return array_keys($this->ids);
}
/**
* Set multiple ids
*
* This overwrites any existing ids
*
* @param array $ids
* @return self Provides fluent interface
*/
public function setIds($ids)
{
$this->clearIds();
$this->addIds($ids);
return $this;
}
/**
* Set a custom document class
*
* This class should implement the document interface
*
* @param string $value classname
* @return self Provides fluent interface
*/
public function setDocumentClass($value)
{
return $this->setOption('documentclass', $value);
}
/**
* Get the current documentclass option
*
* The value is a classname, not an instance
*
* @return string
*/
public function getDocumentClass()
{
return $this->getOption('documentclass');
}
/**
* No components for this querytype
*
* @return array
*/
public function getComponents()
{
return array();
}
}
<?php
/**
* Copyright 2012 Bas de Nooijer. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this listof conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 HOLDER 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.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the copyright holder.
*
* @copyright Copyright 2012 Bas de Nooijer <solarium@raspberry.nl>
* @license http://github.com/basdenooijer/solarium/raw/master/COPYING
* @link http://www.solarium-project.org/
*/
/**
* @namespace
*/
namespace Solarium\QueryType\RealtimeGet;
use Solarium\Core\Client\Request;
use Solarium\Core\Query\RequestBuilder as BaseRequestBuilder;
use Solarium\Core\Query\QueryInterface;
/**
* Build a RealtimeGet request
*/
class RequestBuilder extends BaseRequestBuilder
{
/**
* Build request for a ping query
*
* @param Query $query
* @return Request
*/
public function build(QueryInterface $query)
{
$request = parent::build($query);
$request->setMethod(Request::METHOD_GET);
$request->addParam('ids', implode(',', $query->getIds()));
return $request;
}
}
<?php
/**
* Copyright 2011 Bas de Nooijer. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this listof conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 HOLDER 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.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the copyright holder.
*
* @copyright Copyright 2011 Bas de Nooijer <solarium@raspberry.nl>
* @license http://github.com/basdenooijer/solarium/raw/master/COPYING
* @link http://www.solarium-project.org/
*/
/**
* @namespace
*/
namespace Solarium\QueryType\RealtimeGet;
use Solarium\QueryType\Select\Result\Result as BaseResult;
use Solarium\QueryType\Select\Result\DocumentInterface;
/**
* RealtimeGet query results
*
* Extends the standard select result with a accessor method for the first document
*/
class Result extends BaseResult implements \IteratorAggregate, \Countable
{
/**
* Get first document in set
*
* @return DocumentInterface
*/
public function getDocument()
{
$docs = $this->getDocuments();
return reset($docs);
}
}
......@@ -44,6 +44,7 @@ use Solarium\QueryType\Select\RequestBuilder\Component\DistributedSearch as Requ
* Distributed Search (sharding) component
*
* @link http://wiki.apache.org/solr/DistributedSearch
* @link http://wiki.apache.org/solr/SolrCloud/
*/
class DistributedSearch extends Component
{
......@@ -55,6 +56,13 @@ class DistributedSearch extends Component
*/
protected $shards = array();
/**
* Requests will be distributed across collections in this list
*
* @var array
*/
protected $collections = array();
/**
* Get component type
*
......@@ -100,6 +108,9 @@ class DistributedSearch extends Component
case 'shards':
$this->setShards($value);
break;
case 'collections':
$this->setCollections($value);
break;
}
}
}
......@@ -234,4 +245,89 @@ class DistributedSearch extends Component
{
return $this->getOption('shardhandler');
}
/**
* Add a collection
*
* @param string $key unique string
* @param string $collection The syntax is host:port/base_url
* @return self Provides fluent interface
* @link http://wiki.apache.org/solr/SolrCloud/
*/
public function addCollection($key, $collection)
{
$this->collections[$key] = $collection;
return $this;
}
/**
* Add multiple collections
*
* @param array $collections
* @return self Provides fluent interface
*/
public function addCollections(array $collections)
{
foreach ($collections as $key => $collection) {
$this->addCollection($key, $collection);
}
return $this;
}
/**
* Remove a collection
*
* @param string $key
* @return self Provides fluent interface
*/
public function removeCollection($key)
{
if (isset($this->collections[$key])) {
unset($this->collections[$key]);
}
return $this;
}
/**
* Remove all collections
*
* @return self Provides fluent interface
*/
public function clearCollections()
{
$this->collections = array();
return $this;
}
/**
* Set multiple collections
*
* This overwrites any existing collections
*
* @param array $collections Associative array of collections
* @return self Provides fluent interface
*/
public function setCollections(array $collections)
{
$this->clearCollections();
$this->addCollections($collections);
return $this;
}
/**
* Get a list of the collections
*
* @return array
*/
public function getCollections()
{
return $this->collections;
}
}
......@@ -38,6 +38,7 @@
*/
namespace Solarium\QueryType\Select\Query\Component;
use Solarium\QueryType\Select\Query\Query as SelectQuery;
use Solarium\QueryType\Select\RequestBuilder\Component\EdisMax as RequestBuilder;
/**
* EdisMax component
......@@ -66,6 +67,16 @@ class EdisMax extends DisMax
return SelectQuery::COMPONENT_EDISMAX;
}
/**
* Get a requestbuilder for this query
*
* @return RequestBuilder
*/
public function getRequestBuilder()
{
return new RequestBuilder;
}
/**
* Set BoostFunctionsMult option
*
......
<?php
/**
* Copyright 2011 Bas de Nooijer. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this listof conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 HOLDER 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.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the copyright holder.
*
* @copyright Copyright 2011 Bas de Nooijer <solarium@raspberry.nl>
* @license http://github.com/basdenooijer/solarium/raw/master/COPYING
* @link http://www.solarium-project.org/
*/
/**
* @namespace
*/
namespace Solarium\QueryType\Select\Query\Component\Facet;
use Solarium\QueryType\Select\Query\Component\FacetSet;
/**
* Facet pivot
*
* @link http://wiki.apache.org/solr/SimpleFacetParameters#Pivot_.28ie_Decision_Tree.29_Faceting
*/
class Pivot extends Facet
{
/**
* Fields to use
*
* @var array
*/
protected $fields = array();
/**
* Initialize options
*
* @return void
*/
protected function init()
{
if (isset($this->options['fields'])) {
$this->addFields($this->options['fields']);
}
}
/**
* Get the facet type
*
* @return string
*/
public function getType()
{
return FacetSet::FACET_PIVOT;
}
/**
* Set the facet mincount
*
* @param int $minCount
* @return self Provides fluent interface
*/
public function setMinCount($minCount)
{
return $this->setOption('mincount', $minCount);
}
/**
* Get the facet mincount
*
* @return int
*/
public function getMinCount()
{
return $this->getOption('mincount');
}
/**
* Specify a field to return in the resultset
*
* @param string $field
* @return self Provides fluent interface
*/
public function addField($field)
{
$field = trim($field);
$this->fields[$field] = true;
return $this;
}
/**
* Specify multiple fields to return in the resultset
*
* @param string|array $fields can be an array or string with comma
* separated fieldnames
*
* @return self Provides fluent interface
*/
public function addFields($fields)
{
if (is_string($fields)) {
$fields = explode(',', $fields);
}
foreach ($fields as $field) {
$this->addField($field);
}
return $this;
}
/**
* Remove a field from the field list
*
* @param string $field
* @return self Provides fluent interface
*/
public function removeField($field)
{
if (isset($this->fields[$field])) {
unset($this->fields[$field]);
}
return $this;
}
/**
* Remove all fields from the field list.
*
* @return self Provides fluent interface
*/
public function clearFields()
{
$this->fields = array();
return $this;
}
/**
* Get the list of fields
*
* @return array
*/
public function getFields()
{
return array_keys($this->fields);
}
/**
* Set multiple fields
*
* This overwrites any existing fields
*
* @param array $fields
* @return self Provides fluent interface
*/
public function setFields($fields)
{
$this->clearFields();
$this->addFields($fields);
return $this;
}
}
......@@ -72,6 +72,11 @@ class FacetSet extends Component
*/
const FACET_RANGE = 'range';
/**
* Facet type pivot
*/
const FACET_PIVOT = 'pivot';
/**
* Facet type mapping
*
......@@ -82,6 +87,7 @@ class FacetSet extends Component
self::FACET_QUERY => 'Solarium\QueryType\Select\Query\Component\Facet\Query',
self::FACET_MULTIQUERY => 'Solarium\QueryType\Select\Query\Component\Facet\MultiQuery',
self::FACET_RANGE => 'Solarium\QueryType\Select\Query\Component\Facet\Range',
self::FACET_PIVOT => 'Solarium\QueryType\Select\Query\Component\Facet\Pivot',
);
/**
......@@ -508,4 +514,16 @@ class FacetSet extends Component
return $this->createFacet(self::FACET_RANGE, $options, $add);
}
/**
* Get a facet pivot instance
*
* @param mixed $options
* @param bool $add
* @return Facet\Pivot
*/
public function createFacetPivot($options = null, $add = true)
{
return $this->createFacet(self::FACET_PIVOT, $options, $add);
}
}
......@@ -60,6 +60,26 @@ class Highlighting extends Component
*/
const FRAGMENTER_REGEX = 'regex';
/**
* Value for BoundaryScanner type
*/
const BOUNDARYSCANNER_TYPE_CHARACTER = 'CHARACTER';
/**
* Value for BoundaryScanner type
*/
const BOUNDARYSCANNER_TYPE_WORD = 'WORD';
/**
* Value for BoundaryScanner type
*/
const BOUNDARYSCANNER_TYPE_SENTENCE = 'SENTENCE';
/**
* Value for BoundaryScanner type
*/
const BOUNDARYSCANNER_TYPE_LINE = 'LINE';
/**
* Array of fields for highlighting
*
......@@ -774,4 +794,110 @@ class Highlighting extends Component
return $this->getOption('multivaluedseparatorchar');
}
/**
* Set boundaryscannermaxscan option
*
* @param int $maximum
* @return self Provides fluent interface
*/
public function setBoundaryScannerMaxScan($maximum)
{
return $this->setOption('boundaryscannermaxscan', $maximum);
}
/**
* Get boundaryscannermaxscan option
*
* @return int|null
*/
public function getBoundaryScannerMaxScan()
{
return $this->getOption('boundaryscannermaxscan');
}
/**
* Set boundaryscannerchars option
*
* @param string $chars
* @return self Provides fluent interface
*/
public function setBoundaryScannerChars($chars)
{
return $this->setOption('boundaryscannerchars', $chars);
}
/**
* Get boundaryscannerchars option
*
* @return string|null
*/
public function getBoundaryScannerChars()
{
return $this->getOption('boundaryscannerchars');
}
/**
* Set boundaryscannertype option
*
* @param string $type
* @return self Provides fluent interface
*/
public function setBoundaryScannerType($type)
{
return $this->setOption('boundaryscannertype', $type);
}
/**
* Get boundaryscannertype option
*
* @return string|null
*/
public function getBoundaryScannerType()
{
return $this->getOption('boundaryscannertype');
}
/**
* Set boundaryscannerlanguage option
*
* @param string $language
* @return self Provides fluent interface
*/
public function setBoundaryScannerLanguage($language)
{
return $this->setOption('boundaryscannerlanguage', $language);
}
/**
* Get boundaryscannerlanguage option
*
* @return string|null
*/
public function getBoundaryScannerLanguage()
{
return $this->getOption('boundaryscannerlanguage');
}
/**
* Set boundaryscannercountry option
*
* @param string $country
* @return self Provides fluent interface
*/
public function setBoundaryScannerCountry($country)
{
return $this->setOption('boundaryscannercountry', $country);
}
/**
* Get boundaryscannercountry option
*
* @return string|null
*/
public function getBoundaryScannerCountry()
{
return $this->getOption('boundaryscannercountry');
}
}
......@@ -48,6 +48,13 @@ use Solarium\QueryType\Select\ResponseParser\Component\Spellcheck as ResponsePar
*/
class Spellcheck extends Component
{
/**
* Used to further customize collation parameters
* @var array
*/
protected $collateParams = array();
/**
* Get component type
*
......@@ -366,4 +373,25 @@ class Spellcheck extends Component
return $this->getOption('accuracy');
}
/**
* Set a collation param
* @param string $param
* @param mixed $value
* @return self Provides fluent interface
*/
public function setCollateParam($param, $value)
{
$this->collateParams[$param] = $value;
return $this;
}
/**
* Returns the array of collate params
* @return array
*/
public function getCollateParams()
{
return $this->collateParams;
}
}
......@@ -55,13 +55,20 @@ class DistributedSearch implements ComponentRequestBuilderInterface
*/
public function buildComponent($component, $request)
{
// add shard fields to request
// add shards to request
$shards = array_values($component->getShards());
if (count($shards)) {
$request->addParam('shards', implode(',', $shards));
}
$request->addParam('shards.qt', $component->getShardRequestHandler());
// add collections to request
$collections = array_values($component->getCollections());
if (count($collections)) {
$request->addParam('collection', implode(',', $collections));
}
return $request;
}
}
......@@ -44,6 +44,7 @@ use Solarium\QueryType\Select\Query\Component\Facet\Field as FacetField;
use Solarium\QueryType\Select\Query\Component\Facet\MultiQuery as FacetMultiQuery;
use Solarium\QueryType\Select\Query\Component\Facet\Query as FacetQuery;
use Solarium\QueryType\Select\Query\Component\Facet\Range as FacetRange;
use Solarium\QueryType\Select\Query\Component\Facet\Pivot as FacetPivot;
use Solarium\Exception\UnexpectedValueException;
/**
......@@ -89,6 +90,9 @@ class FacetSet extends RequestBuilder implements ComponentRequestBuilderInterfac
case FacetsetComponent::FACET_RANGE:
$this->addFacetRange($request, $facet);
break;
case FacetsetComponent::FACET_PIVOT:
$this->addFacetPivot($request, $facet);
break;
default:
throw new UnexpectedValueException('Unknown facet type');
}
......@@ -190,4 +194,17 @@ class FacetSet extends RequestBuilder implements ComponentRequestBuilderInterfac
$request->addParam("f.$field.facet.range.include", $includeValue);
}
}
/**
* Add params for a range facet to request
*
* @param Request $request
* @param FacetPivot $facet
* @return void
*/
public function addFacetPivot($request, $facet)
{
$request->addParam('facet.pivot', implode(',', $facet->getFields()));
$request->addParam('facet.pivot.mincount', $facet->getMinCount(), true);
}
}
......@@ -85,6 +85,11 @@ class Highlighting implements ComponentRequestBuilderInterface
$request->addParam('hl.q', $component->getQuery());
$request->addParam('hl.phraseLimit', $component->getPhraseLimit());
$request->addParam('hl.multiValuedSeparatorChar', $component->getMultiValuedSeparatorChar());
$request->addParam('hl.bs.maxScan', $component->getBoundaryScannerMaxScan());
$request->addParam('hl.bs.chars', $component->getBoundaryScannerChars());
$request->addParam('hl.bs.type', $component->getBoundaryScannerType());
$request->addParam('hl.bs.language', $component->getBoundaryScannerLanguage());
$request->addParam('hl.bs.country', $component->getBoundaryScannerCountry());
// set per-field highlighting params
foreach ($component->getFields() as $field) {
......
......@@ -72,6 +72,10 @@ class Spellcheck implements ComponentRequestBuilderInterface
$request->addParam('spellcheck.collateExtendedResults', $component->getCollateExtendedResults());
$request->addParam('spellcheck.accuracy', $component->getAccuracy());
foreach ( $component->getCollateParams() as $param => $value ) {
$request->addParam('spellcheck.collateParam.'.$param, $value);
}
return $request;
}
}
......@@ -43,11 +43,13 @@ use Solarium\QueryType\Select\Query\Component\Facet\Field as QueryFacetField;
use Solarium\QueryType\Select\Query\Component\Facet\Query as QueryFacetQuery;
use Solarium\QueryType\Select\Query\Component\Facet\MultiQuery as QueryFacetMultiQuery;
use Solarium\QueryType\Select\Query\Component\Facet\Range as QueryFacetRange;
use Solarium\QueryType\Select\Query\Component\Facet\Pivot as QueryFacetPivot;
use Solarium\QueryType\Select\Result\FacetSet as ResultFacetSet;
use Solarium\QueryType\Select\Result\Facet\Field as ResultFacetField;
use Solarium\QueryType\Select\Result\Facet\Query as ResultFacetQuery;
use Solarium\QueryType\Select\Result\Facet\MultiQuery as ResultFacetMultiQuery;
use Solarium\QueryType\Select\Result\Facet\Range as ResultFacetRange;
use Solarium\QueryType\Select\Result\Facet\Pivot\Pivot as ResultFacetPivot;
use Solarium\Exception\RuntimeException;
use Solarium\Core\Query\ResponseParser as ResponseParserAbstract;
......@@ -81,9 +83,15 @@ class FacetSet extends ResponseParserAbstract implements ComponentParserInterfac
case 'facet_ranges':
$method = 'createFacetRange';
break;
case 'facet_pivot':
$method = 'createFacetPivot';
break;
}
foreach ($facets as $k => $facet) {
$facetSet->$method($k);
$facetObject = $facetSet->$method($k);
if ($key == 'facet_pivot') {
$facetObject->setFields($k);
}
}
}
}
......@@ -104,6 +112,9 @@ class FacetSet extends ResponseParserAbstract implements ComponentParserInterfac
case QueryFacetSet::FACET_RANGE:
$result = $this->facetRange($query, $facet, $data);
break;
case QueryFacetSet::FACET_PIVOT:
$result = $this->facetPivot($query, $facet, $data);
break;
default:
throw new RuntimeException('Unknown facet type');
}
......@@ -218,4 +229,21 @@ class FacetSet extends ResponseParserAbstract implements ComponentParserInterfac
}
}
/**
* Add a facet result for a range facet
*
* @param Query $query
* @param QueryFacetPivot $facet
* @param array $data
* @return ResultFacetPivot
*/
protected function facetPivot($query, $facet, $data)
{
$key = implode(',', $facet->getFields());
if (isset($data['facet_counts']['facet_pivot'][$key])) {
$data = $data['facet_counts']['facet_pivot'][$key];
return new ResultFacetPivot($data);
}
}
}
......@@ -112,7 +112,7 @@ class Spellcheck extends ResponseParserAbstract implements ComponentParserInterf
$collations[] = new Collation($values, null, array());
} else if (is_array($values) && isset($values[0]) && is_string($values[0]) && $values[0] !== 'collationQuery') {
} elseif (is_array($values) && isset($values[0]) && is_string($values[0]) && $values[0] !== 'collationQuery') {
foreach ($values as $value) {
$collations[] = new Collation($value, null, array());
......@@ -182,16 +182,19 @@ class Spellcheck extends ResponseParserAbstract implements ComponentParserInterf
$endOffset = (isset($value['endOffset'])) ? $value['endOffset'] : null;
$originalFrequency = (isset($value['origFreq'])) ? $value['origFreq'] : null;
if (is_string($value['suggestion'][0])) {
$word = $value['suggestion'][0];
$frequency = null;
} else {
$word = $value['suggestion'][0]['word'];
$frequency = $value['suggestion'][0]['freq'];
$words = array();
foreach($value['suggestion'] as $suggestion) {
if (is_string($suggestion)) {
$suggestion = array(
'word' => $suggestion,
'freq' => null,
);
}
$words[] = $suggestion;
}
return new Suggestion(
$numFound, $startOffset, $endOffset, $originalFrequency, $word, $frequency
$numFound, $startOffset, $endOffset, $originalFrequency, $words
);
}
}
......@@ -68,7 +68,7 @@ class ResponseParser extends ResponseParserAbstract implements ResponseParserInt
// create document instances
$documentClass = $query->getOption('documentclass');
$classes = class_implements($documentClass);
if (!in_array('Solarium\QueryType\Select\Result\DocumentInterface',$classes) && !in_array('Solarium\QueryType\Update\Query\DocumentInterface',$classes)) {
if (!in_array('Solarium\QueryType\Select\Result\DocumentInterface',$classes) && !in_array('Solarium\QueryType\Update\Query\Document\DocumentInterface',$classes)) {
throw new RuntimeException('The result document class must implement a document interface');
}
......
<?php
/**
* Copyright 2011 Bas de Nooijer. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this listof conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 HOLDER 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.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the copyright holder.
*
* @copyright Copyright 2011 Bas de Nooijer <solarium@raspberry.nl>
* @license http://github.com/basdenooijer/solarium/raw/master/COPYING
* @link http://www.solarium-project.org/
*/
/**
* @namespace
*/
namespace Solarium\QueryType\Select\Result\Facet\Pivot;
/**
* Select field pivot result
*
*/
class Pivot implements \IteratorAggregate, \Countable
{
/**
* Value array
*
* @var array
*/
protected $pivot = array();
/**
* Constructor
*
* @param array $data
* @return void
*/
public function __construct($data)
{
foreach ($data as $pivotData) {
$this->pivot[] = new PivotItem($pivotData);
}
}
/**
* Get pivot results
*
* @return Pivot[]
*/
public function getPivot()
{
return $this->pivot;
}
/**
* IteratorAggregate implementation
*
* @return \ArrayIterator
*/
public function getIterator()
{
return new \ArrayIterator($this->pivot);
}
/**
* Countable implementation
*
* @return int
*/
public function count()
{
return count($this->pivot);
}
}
<?php
/**
* Copyright 2011 Bas de Nooijer. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this listof conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 HOLDER 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.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the copyright holder.
*
* @copyright Copyright 2011 Bas de Nooijer <solarium@raspberry.nl>
* @license http://github.com/basdenooijer/solarium/raw/master/COPYING
* @link http://www.solarium-project.org/
*/
/**
* @namespace
*/
namespace Solarium\QueryType\Select\Result\Facet\Pivot;
/**
* Select field pivot result
*
*/
class PivotItem extends Pivot
{
/**
* Field name
*
* @var string
*/
protected $field;
/**
* Field value
*
* @var mixed
*/
protected $value;
/**
* Count
*
* @var int
*/
protected $count;
/**
* Constructor
*
* @param array $data
* @return void
*/
public function __construct($data)
{
$this->field = $data['field'];
$this->value = $data['value'];
$this->count = $data['count'];
if (isset($data['pivot'])) {
foreach ($data['pivot'] as $pivotData) {
$this->pivot[] = new PivotItem($pivotData);
}
}
}
/**
* Get field name
*
* @return string
*/
public function getField()
{
return $this->field;
}
/**
* Get field value
*
* @return mixed
*/
public function getValue()
{
return $this->value;
}
/**
* Get count
*
* @return int
*/
public function getCount()
{
return $this->count;
}
}
......@@ -51,17 +51,15 @@ class Suggestion
* @param int $startOffset
* @param int $endOffset
* @param int $originalFrequency
* @param string $word
* @param int $frequency
* @param array $words
*/
public function __construct($numFound, $startOffset, $endOffset, $originalFrequency, $word, $frequency)
public function __construct($numFound, $startOffset, $endOffset, $originalFrequency, $words)
{
$this->numFound = $numFound;
$this->startOffset = $startOffset;
$this->endOffset = $endOffset;
$this->originalFrequency = $originalFrequency;
$this->word = $word;
$this->frequency = $frequency;
$this->words = $words;
}
/**
......@@ -107,13 +105,28 @@ class Suggestion
}
/**
* Get word
* Get first word
*
* @return string
* @return string|null
*/
public function getWord()
{
return $this->word;
$word = reset($this->words);
if (isset($word['word'])) {
return $word['word'];
} else {
return $word;
}
}
/**
* Get all words (and frequencies)
*
* @return array
*/
public function getWords()
{
return $this->words;
}
/**
......@@ -125,7 +138,12 @@ class Suggestion
*/
public function getFrequency()
{
return $this->frequency;
$word = reset($this->words);
if (isset($word['freq'])) {
return $word['freq'];
} else {
return null;
}
}
}
......@@ -38,7 +38,7 @@
*/
namespace Solarium\QueryType\Update\Query\Command;
use Solarium\QueryType\Update\Query\Query as UpdateQuery;
use Solarium\QueryType\Update\Query\Document;
use Solarium\QueryType\Update\Query\Document\Document;
use Solarium\Exception\RuntimeException;
/**
......
......@@ -36,8 +36,9 @@
/**
* @namespace
*/
namespace Solarium\QueryType\Update\Query;
namespace Solarium\QueryType\Update\Query\Document;
use Solarium\QueryType\Select\Result\AbstractDocument;
use Solarium\Exception\RuntimeException;
/**
* Read/Write Solr document
......@@ -51,9 +52,52 @@ use Solarium\QueryType\Select\Result\AbstractDocument;
* is not recommended. Most Solr indexes have fields that are indexed and not
* stored. You will loose that data because it is impossible to retrieve it from
* Solr. Always update from the original data source.
*
* Atomic updates are also support, using the field modifiers
*/
class Document extends AbstractDocument implements DocumentInterface
{
/**
* Directive to set a value using atomic updates
*
* @var string
*/
const MODIFIER_SET = 'set';
/**
* Directive to increment an integer value using atomic updates
*
* @var string
*/
const MODIFIER_INC = 'inc';
/**
* Directive to append a value (e.g. multivalued fields) using atomic updates
*
* @var string
*/
const MODIFIER_ADD = 'add';
/**
* This value has the same effect as not setting a version
*
* @var int
*/
const VERSION_DONT_CARE = 0;
/**
* This value requires an existing document with the same key, but no specific version
*
* @var int
*/
const VERSION_MUST_EXIST = 1;
/**
* This value requires that no document with the same key exists (so no automatic overwrite like default)
*
* @var int
*/
const VERSION_MUST_NOT_EXIST = -1;
/**
* Document boost value
......@@ -62,6 +106,20 @@ class Document extends AbstractDocument implements DocumentInterface
*/
protected $boost = null;
/**
* Allows us to determine what kind of atomic update we want to set
*
* @var array
*/
protected $modifiers = array();
/**
* This field needs to be explicitly set to observe the rules of atomic updates
*
* @var string
*/
protected $key;
/**
* Field boosts
*
......@@ -71,16 +129,27 @@ class Document extends AbstractDocument implements DocumentInterface
*/
protected $fieldBoosts;
/**
* Version value
*
* Can be used for updating using Solr's optimistic concurrency control
*
* @var int
*/
protected $version;
/**
* Constructor
*
* @param array $fields
* @param array $boosts
* @param array $modifiers
*/
public function __construct(array $fields = array(), array $boosts = array())
public function __construct(array $fields = array(), array $boosts = array(), array $modifiers = array())
{
$this->fields = $fields;
$this->fieldBoosts = $boosts;
$this->modifiers = $modifiers;
}
/**
......@@ -92,12 +161,13 @@ class Document extends AbstractDocument implements DocumentInterface
* @param string $key
* @param mixed $value
* @param float $boost
* @param string $modifier
* @return self Provides fluent interface
*/
public function addField($key, $value, $boost = null)
public function addField($key, $value, $boost = null, $modifier = null)
{
if (!isset($this->fields[$key])) {
$this->setField($key, $value, $boost);
$this->setField($key, $value, $boost, $modifier);
} else {
// convert single value to array if needed
if (!is_array($this->fields[$key])) {
......@@ -106,6 +176,9 @@ class Document extends AbstractDocument implements DocumentInterface
$this->fields[$key][] = $value;
$this->setFieldBoost($key, $boost);
if ($modifier !== null) {
$this->setFieldModifier($key, $modifier);
}
}
return $this;
......@@ -121,15 +194,19 @@ class Document extends AbstractDocument implements DocumentInterface
* @param string $key
* @param mixed $value
* @param float $boost
* @param string $modifier
* @return self Provides fluent interface
*/
public function setField($key, $value, $boost = null)
public function setField($key, $value, $boost = null, $modifier = null)
{
if ($value === null) {
$this->removeField($key);
} else {
$this->fields[$key] = $value;
$this->setFieldBoost($key, $boost);
if ($modifier !== null) {
$this->setFieldModifier($key, $modifier);
}
}
return $this;
......@@ -225,6 +302,7 @@ class Document extends AbstractDocument implements DocumentInterface
{
$this->fields = array();
$this->fieldBoosts = array();
$this->modifiers = array();
return $this;
}
......@@ -261,4 +339,90 @@ class Document extends AbstractDocument implements DocumentInterface
$this->removeField($name);
}
/**
* Sets the uniquely identifying key for use in atomic updating
*
* You can set an existing field as key by supplying that field name as key, or add a new field by also supplying a
* value.
*
* @param string $key
* @param mixed $value
* @return self Provides fluent interface
*/
public function setKey($key, $value = null)
{
$this->key = $key;
if ($value !== null) {
$this->addField($key, $value);
}
return $this;
}
/**
* Sets the modifier type for the provided field
*
* @param string $key
* @param string $modifier
* @throws RuntimeException
* @return self
*/
public function setFieldModifier($key, $modifier = null)
{
if (! in_array($modifier, array(self::MODIFIER_ADD, self::MODIFIER_INC, self::MODIFIER_SET)) ) {
throw new RuntimeException('Attempt to set an atomic update modifier that is not supported');
}
$this->modifiers[$key] = $modifier;
return $this;
}
/**
* Returns the appropriate modifier for atomic updates.
*
* @param string $key
* @return null|string
*/
public function getFieldModifier($key)
{
return isset($this->modifiers[$key]) ? $this->modifiers[$key] : null;
}
/**
* Get fields
*
* Adds validation for atomicUpdates
*
* @return array
*/
public function getFields()
{
if (count($this->modifiers) > 0 && ($this->key == null || !isset($this->fields[$this->key]))) {
throw new RuntimeException(
'A document that uses modifiers (atomic updates) must have a key defined before it is used'
);
}
return parent::getFields();
}
/**
* Set version
*
* @param int $version
* @return self
*/
public function setVersion($version)
{
$this->version = $version;
return $this;
}
/**
* Get version
*
* @return int
*/
public function getVersion()
{
return $this->version;
}
}
......@@ -36,7 +36,7 @@
/**
* @namespace
*/
namespace Solarium\QueryType\Update\Query;
namespace Solarium\QueryType\Update\Query\Document;
/**
* Solr update document interface
......@@ -48,7 +48,9 @@ interface DocumentInterface
* Constructor
*
* @param array $fields
* @param array $boosts
* @param array $modifiers
*/
public function __construct(array $fields = array(), array $boosts = array());
public function __construct(array $fields = array(), array $boosts = array(), array $modifiers = array());
}
......@@ -106,7 +106,7 @@ class Query extends BaseQuery
protected $options = array(
'handler' => 'update',
'resultclass' => 'Solarium\QueryType\Update\Result',
'documentclass' => 'Solarium\QueryType\Update\Query\Document',
'documentclass' => 'Solarium\QueryType\Update\Query\Document\Document',
'omitheader' => false,
);
......@@ -276,10 +276,15 @@ class Query extends BaseQuery
* create you own command instance and use the add method.
*
* @param string $query
* @param array $bind Bind values for placeholders in the query string
* @return self Provides fluent interface
*/
public function addDeleteQuery($query)
public function addDeleteQuery($query, $bind = null)
{
if (!is_null($bind)) {
$query = $this->getHelper()->assemble($query, $bind);
}
$delete = new DeleteCommand;
$delete->addQuery($query);
......
......@@ -80,7 +80,7 @@ class RequestBuilder extends BaseRequestBuilder
foreach ($query->getCommands() as $command) {
switch ($command->getType()) {
case UpdateQuery::COMMAND_ADD:
$xml .= $this->buildAddXml($command);
$xml .= $this->buildAddXml($command, $query);
break;
case UpdateQuery::COMMAND_DELETE:
$xml .= $this->buildDeleteXml($command);
......@@ -108,9 +108,10 @@ class RequestBuilder extends BaseRequestBuilder
* Build XML for an add command
*
* @param Query\Command\Add $command
* @param UpdateQuery $query
* @return string
*/
public function buildAddXml($command)
public function buildAddXml($command, $query = null)
{
$xml = '<add';
$xml .= $this->boolAttrib('overwrite', $command->getOverwrite());
......@@ -124,15 +125,21 @@ class RequestBuilder extends BaseRequestBuilder
foreach ($doc->getFields() as $name => $value) {
$boost = $doc->getFieldBoost($name);
$modifier = $doc->getFieldModifier($name);
if (is_array($value)) {
foreach ($value as $multival) {
$xml .= $this->buildFieldXml($name, $boost, $multival);
$xml .= $this->buildFieldXml($name, $boost, $multival, $modifier, $query);
}
} else {
$xml .= $this->buildFieldXml($name, $boost, $value);
$xml .= $this->buildFieldXml($name, $boost, $value, $modifier, $query);
}
}
$version = $doc->getVersion();
if ($version !== null) {
$xml .= $this->buildFieldXml('_version_', null, $version);
}
$xml .= '</doc>';
}
......@@ -149,12 +156,19 @@ class RequestBuilder extends BaseRequestBuilder
* @param string $name
* @param float $boost
* @param mixed $value
* @param string $modifier
* @param UpdateQuery $query
* @return string
*/
protected function buildFieldXml($name, $boost, $value)
protected function buildFieldXml($name, $boost, $value, $modifier = null, $query = null)
{
if ($value instanceof \DateTime) {
$value = $query->getHelper()->formatDate($value);
}
$xml = '<field name="' . $name . '"';
$xml .= $this->attrib('boost', $boost);
$xml .= $this->attrib('update', $modifier);
$xml .= '>' . htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8');
$xml .= '</field>';
......
......@@ -55,15 +55,18 @@ class CurlTest extends \PHPUnit_Framework_TestCase
{
$data = 'data';
$headers = array('X-dummy: data');
$handler = curl_init();
// this should be ok, no exception
$this->adapter->check($data, $headers);
$this->adapter->check($data, $headers, $handler);
$data = '';
$headers = array();
$this->setExpectedException('Solarium\Exception\HttpException');
$this->adapter->check($data, $headers);
$this->adapter->check($data, $headers, $handler);
curl_close($handler);
}
public function testExecute()
......
......@@ -173,6 +173,13 @@ class ClientTest extends \PHPUnit_Framework_TestCase
$this->assertThat($endpoint, $this->isInstanceOf('Solarium\Core\Client\Endpoint'));
}
public function testCreateEndpointWithSetAsDefault()
{
$this->client->createEndpoint('key3', true);
$endpoint = $this->client->getEndpoint();
$this->assertEquals('key3', $endpoint->getKey());
}
public function testCreateEndpointWithArray()
{
$options = array(
......
......@@ -47,11 +47,13 @@ class EndpointTest extends \PHPUnit_Framework_TestCase
public function testConfigMode()
{
$options = array(
'host' => '192.168.0.1',
'port' => 123,
'path' => '/mysolr/',
'core' => 'mycore',
'timeout' => 3,
'host' => '192.168.0.1',
'port' => 123,
'path' => '/mysolr/',
'core' => 'mycore',
'timeout' => 3,
'username' => 'x',
'password' => 'y'
);
$this->endpoint->setOptions($options);
......@@ -110,4 +112,50 @@ class EndpointTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('http://myserver:123/mypath/mycore/', $this->endpoint->getBaseUri());
}
public function testGetAndSetAuthentication()
{
$user = 'someone';
$pass = 'S0M3p455';
$this->endpoint->setAuthentication($user, $pass);
$this->assertEquals(
array(
'username' => $user,
'password' => $pass,
),
$this->endpoint->getAuthentication()
);
}
public function testToString()
{
$options = array(
'host' => '192.168.0.1',
'port' => 123,
'path' => '/mysolr/',
'core' => 'mycore',
'timeout' => 3,
'username' => 'x',
'password' => 'y'
);
$this->endpoint->setOptions($options);
$this->assertEquals(
'Solarium\Core\Client\Endpoint::__toString
base uri: http://192.168.0.1:123/mysolr/mycore/
host: 192.168.0.1
port: 123
path: /mysolr
core: mycore
timeout: 3
authentication: Array
(
[username] => x
[password] => y
)
',
(string) $this->endpoint
);
}
}
......@@ -207,8 +207,8 @@ class HelperTest extends \PHPUnit_Framework_TestCase
public function testEscapeTerm()
{
$this->assertEquals(
'a\\+b',
$this->helper->escapeTerm('a+b')
'a\\+b\/c',
$this->helper->escapeTerm('a+b/c')
);
}
......@@ -380,4 +380,28 @@ class HelperTest extends \PHPUnit_Framework_TestCase
);
}
public function testQparserTerm()
{
$this->assertEquals(
'{!term f=weight}1.5',
$this->helper->qparserTerm('weight', 1.5)
);
}
public function testCacheControlWithCost()
{
$this->assertEquals(
'{!cache=false cost=6}',
$this->helper->cacheControl(false,6)
);
}
public function testCacheControlWithoutCost()
{
$this->assertEquals(
'{!cache=true}',
$this->helper->cacheControl(true)
);
}
}
......@@ -30,9 +30,11 @@
*/
namespace Solarium\Tests\Plugin\BufferedAdd;
use Solarium\QueryType\Update\Query\Document;
use Solarium\QueryType\Update\Query\Document\Document;
use Solarium\Plugin\BufferedAdd\Event\AddDocument;
use Solarium\Plugin\BufferedAdd\BufferedAdd;
use Solarium\Core\Client\Client;
use Solarium\Plugin\BufferedAdd\Event\Events;
class BufferedAddTest extends \PHPUnit_Framework_TestCase
{
......@@ -93,9 +95,12 @@ class BufferedAddTest extends \PHPUnit_Framework_TestCase
public function testAddDocumentAutoFlush()
{
$observer = $this->getMock('Solarium\Plugin\BufferedAdd\BufferedAdd', array('flush'));
$observer->expects($this->once())->method('flush');
$observer->setBufferSize(1);
$mockUpdate = $this->getMock('Solarium\QueryType\Update\Query\Query', array('addDocuments'));
$mockUpdate->expects($this->exactly(2))->method('addDocuments');
$mockClient = $this->getMock('Solarium\Core\Client\Client', array('createUpdate', 'update', 'triggerEvent'));
$mockClient->expects($this->exactly(3))->method('createUpdate')->will($this->returnValue($mockUpdate));
$mockClient->expects($this->exactly(2))->method('update')->will($this->returnValue('dummyResult'));
$doc1 = new Document();
$doc1->id = '123';
......@@ -107,7 +112,10 @@ class BufferedAddTest extends \PHPUnit_Framework_TestCase
$docs = array($doc1, $doc2);
$observer->addDocuments($docs);
$plugin = new BufferedAdd();
$plugin->initPlugin($mockClient, array());
$plugin->setBufferSize(1);
$plugin->addDocuments($docs);
}
public function testClear()
......@@ -166,4 +174,25 @@ class BufferedAddTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('dummyResult', $plugin->commit(true, false, true, false));
}
public function testAddDocumentEventIsTriggered()
{
$data = array('id' => '123', 'name' => 'test');
$doc = new Document($data);
$expectedEvent = new AddDocument($doc);
$mockEventDispatcher = $this->getMock('Solarium\QueryType\Update\Query\Query', array('dispatch'));
$mockEventDispatcher
->expects($this->once())
->method('dispatch')
->with($this->equalTo(Events::ADD_DOCUMENT), $this->equalTo($expectedEvent));
$mockClient = $this->getMock('Solarium\Core\Client\Client', array('getEventDispatcher'));
$mockClient->expects($this->once())->method('getEventDispatcher')->will($this->returnValue($mockEventDispatcher));
$plugin = new BufferedAdd();
$plugin->initPlugin($mockClient, array());
$plugin->addDocument($doc);
}
}
<?php
/**
* Copyright 2011 Bas de Nooijer. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this listof conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 HOLDER 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.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the copyright holder.
*/
namespace Solarium\Tests\Plugin\BufferedAdd\Event;
use Solarium\Plugin\BufferedAdd\Event\AddDocument;
use Solarium\QueryType\Update\Query\Document\Document;
class AddDocumentTest extends \PHPUnit_Framework_TestCase
{
public function testConstructorAndGetters()
{
$document = new Document();
$event = new AddDocument($document);
$this->assertEquals($document, $event->getDocument());
return $event;
}
}
......@@ -33,7 +33,7 @@ namespace Solarium\Tests\QueryType\Analysis\RequestBuilder;
use Solarium\QueryType\Analysis\Query\Document;
use Solarium\QueryType\Analysis\RequestBuilder\Document as DocumentBuilder;
use Solarium\Core\Client\Request;
use Solarium\QueryType\Update\Query\Document as InputDocument;
use Solarium\QueryType\Update\Query\Document\Document as InputDocument;
class DocumentTest extends \PHPUnit_Framework_TestCase
{
......
......@@ -31,7 +31,7 @@
namespace Solarium\Tests\QueryType\Extract;
use Solarium\Core\Client\Client;
use Solarium\QueryType\Update\Query\Document;
use Solarium\QueryType\Update\Query\Document\Document;
use Solarium\QueryType\Extract\Query;
class QueryTest extends \PHPUnit_Framework_TestCase
......
<?php
/**
* Copyright 2011 Bas de Nooijer. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this listof conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 HOLDER 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.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the copyright holder.
*/
namespace Solarium\Tests\QueryType\RealtimeGet;
use Solarium\QueryType\RealtimeGet\Query;
use Solarium\Core\Client\Client;
class QueryTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Query
*/
protected $query;
public function setUp()
{
$this->query = new Query;
}
public function testGetType()
{
$this->assertEquals(Client::QUERY_REALTIME_GET, $this->query->getType());
}
public function testGetResponseParser()
{
$this->assertInstanceOf('Solarium\QueryType\Select\ResponseParser\ResponseParser', $this->query->getResponseParser());
}
public function testGetRequestBuilder()
{
$this->assertInstanceOf('Solarium\QueryType\RealtimeGet\RequestBuilder', $this->query->getRequestBuilder());
}
public function testSetAndGetDocumentClass()
{
$this->query->setDocumentClass('MyDocument');
$this->assertEquals('MyDocument', $this->query->getDocumentClass());
}
public function testGetComponents()
{
$this->assertEquals(array(), $this->query->getComponents());
}
public function testAddId()
{
$expectedIds = $this->query->getIds();
$expectedIds[] = 'newid';
$this->query->addId('newid');
$this->assertEquals($expectedIds, $this->query->getIds());
}
public function testClearIds()
{
$this->query->addId('newid');
$this->query->clearIds();
$this->assertEquals(array(), $this->query->getIds());
}
public function testAddIds()
{
$ids = array('id1','id2');
$this->query->clearIds();
$this->query->addIds($ids);
$this->assertEquals($ids, $this->query->getIds());
}
public function testAddIdsAsStringWithTrim()
{
$this->query->clearIds();
$this->query->addIds('id1, id2');
$this->assertEquals(array('id1','id2'), $this->query->getIds());
}
public function testRemoveId()
{
$this->query->clearIds();
$this->query->addIds(array('id1','id2'));
$this->query->removeId('id1');
$this->assertEquals(array('id2'), $this->query->getIds());
}
public function testSetIds()
{
$this->query->clearIds();
$this->query->addIds(array('id1','id2'));
$this->query->setIds(array('id3','id4'));
$this->assertEquals(array('id3','id4'), $this->query->getIds());
}
}
<?php
/**
* Copyright 2011 Bas de Nooijer. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this listof conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 HOLDER 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.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the copyright holder.
*/
namespace Solarium\Tests\QueryType\RealtimeGet;
use Solarium\Core\Client\Request;
use Solarium\QueryType\RealtimeGet\Query;
use Solarium\QueryType\RealtimeGet\RequestBuilder;
class RequestBuilderTest extends \PHPUnit_Framework_TestCase
{
public function testBuildSingleId()
{
$query = new Query;
$query->addId(123);
$builder = new RequestBuilder();
$request = $builder->build($query);
$this->assertEquals(
$request::METHOD_GET,
$request->getMethod()
);
$this->assertEquals(
'get?omitHeader=true&wt=json&ids=123',
urldecode($request->getUri())
);
}
public function testBuildMultiId()
{
$query = new Query;
$query->addId(123)->addId(456);
$builder = new RequestBuilder();
$request = $builder->build($query);
$this->assertEquals(
$request::METHOD_GET,
$request->getMethod()
);
$this->assertEquals(
'get?omitHeader=true&wt=json&ids=123,456',
urldecode($request->getUri())
);
}
}
<?php
/**
* Copyright 2011 Bas de Nooijer. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this listof conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 HOLDER 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.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the copyright holder.
*/
namespace Solarium\Tests\QueryType\RealtimeGet;
use Solarium\QueryType\RealtimeGet\Result;
use Solarium\QueryType\Select\Result\Document;
class ResultTest extends \PHPUnit_Framework_TestCase
{
protected $doc, $result;
public function setUp()
{
$this->doc = new Document(array('id'=>1,'title'=>'doc1'));
$this->result = new ResultDummy(array($this->doc));
}
public function testGetDocument()
{
$this->assertEquals($this->doc, $this->result->getDocument());
}
}
class ResultDummy extends Result
{
protected $parsed = true;
public function __construct($docs)
{
$this->documents = $docs;
}
}
......@@ -46,7 +46,7 @@ class DistributedSearchTest extends \PHPUnit_Framework_TestCase
$this->distributedSearch = new DistributedSearch;
}
public function testConfigMode()
public function testConfigModeForShards()
{
$options = array(
'shardhandler' => 'dummyhandler',
......@@ -62,6 +62,19 @@ class DistributedSearchTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($options['shards'], $this->distributedSearch->getShards());
}
public function testConfigModeForCollections()
{
$options = array(
'collections' => array(
'collection1' => 'localhost:8983/solr/collection1',
'collection2' => 'localhost:8983/solr/collection2',
)
);
$this->distributedSearch->setOptions($options);
$this->assertEquals($options['collections'], $this->distributedSearch->getCollections());
}
public function testGetType()
{
$this->assertEquals(
......@@ -149,4 +162,68 @@ class DistributedSearchTest extends \PHPUnit_Framework_TestCase
);
}
public function testAddCollection()
{
$this->distributedSearch->addCollection('collection1', 'localhost:8983/solr/collection1');
$collections = $this->distributedSearch->getCollections();
$this->assertEquals(
'localhost:8983/solr/collection1',
$collections['collection1']
);
}
public function testRemoveCollection()
{
$this->distributedSearch->addCollection('collection1', 'localhost:8983/solr/collection1');
$this->distributedSearch->removeCollection('collection1');
$collections = $this->distributedSearch->getCollections();
$this->assertFalse(isset($collections['collection1']));
}
public function testClearCollections()
{
$this->distributedSearch->addCollections(array(
'collection1' => 'localhost:8983/solr/collection1',
'collection2' => 'localhost:8983/solr/collection2',
));
$this->distributedSearch->clearCollections();
$collections = $this->distributedSearch->getCollections();
$this->assertTrue(is_array($collections));
$this->assertEquals(0, count($collections));
}
public function testAddCollections()
{
$collections = array(
'collection1' => 'localhost:8983/solr/collection1',
'collection2' => 'localhost:8983/solr/collection2',
);
$this->distributedSearch->addCollections($collections);
$this->assertEquals($collections, $this->distributedSearch->getCollections());
}
public function testSetCollections()
{
$this->distributedSearch->addCollections(array(
'collection1' => 'localhost:8983/solr/collection1',
'collection2' => 'localhost:8983/solr/collection2',
));
$this->distributedSearch->setCollections(array(
'collection3' => 'localhost:8983/solr/collection3',
'collection4' => 'localhost:8983/solr/collection4',
'collection5' => 'localhost:8983/solr/collection5',
));
$collections = $this->distributedSearch->getCollections();
$this->assertEquals(3, count($collections));
$this->assertEquals(array(
'collection3' => 'localhost:8983/solr/collection3',
'collection4' => 'localhost:8983/solr/collection4',
'collection5' => 'localhost:8983/solr/collection5',
), $collections);
}
}
......@@ -94,6 +94,11 @@ class EdisMaxTest extends \PHPUnit_Framework_TestCase
);
}
public function testGetRequestBuilder()
{
$this->assertInstanceOf('Solarium\QueryType\Select\RequestBuilder\Component\EdisMax', $this->eDisMax->getRequestBuilder());
}
public function testSetAndGetQueryParser()
{
$value = 'dummyparser';
......
<?php
/**
* Copyright 2011 Bas de Nooijer. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this listof conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 HOLDER 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.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the copyright holder.
*/
namespace Solarium\Tests\QueryType\Select\Query\Component\Facet;
use Solarium\QueryType\Select\Query\Component\Facet\Pivot;
use Solarium\QueryType\Select\Query\Component\FacetSet;
class PivotTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Pivot
*/
protected $facet;
public function setUp()
{
$this->facet = new Pivot;
}
public function testConfigMode()
{
$options = array(
'fields' => array('abc','def'),
'mincount' => 5,
);
$this->facet->setOptions($options);
$this->assertEquals($options['fields'], $this->facet->getFields());
$this->assertEquals($options['mincount'], $this->facet->getMinCount());
}
public function testGetType()
{
$this->assertEquals(
FacetSet::FACET_PIVOT,
$this->facet->getType()
);
}
public function testAddField()
{
$expectedFields = $this->facet->getFields();
$expectedFields[] = 'newfield';
$this->facet->addField('newfield');
$this->assertEquals($expectedFields, $this->facet->getFields());
}
public function testClearFields()
{
$this->facet->addField('newfield');
$this->facet->clearFields();
$this->assertEquals(array(), $this->facet->getFields());
}
public function testAddFields()
{
$fields = array('field1','field2');
$this->facet->clearFields();
$this->facet->addFields($fields);
$this->assertEquals($fields, $this->facet->getFields());
}
public function testAddFieldsAsStringWithTrim()
{
$this->facet->clearFields();
$this->facet->addFields('field1, field2');
$this->assertEquals(array('field1','field2'), $this->facet->getFields());
}
public function testRemoveField()
{
$this->facet->clearFields();
$this->facet->addFields(array('field1','field2'));
$this->facet->removeField('field1');
$this->assertEquals(array('field2'), $this->facet->getFields());
}
public function testSetFields()
{
$this->facet->clearFields();
$this->facet->addFields(array('field1','field2'));
$this->facet->setFields(array('field3','field4'));
$this->assertEquals(array('field3','field4'), $this->facet->getFields());
}
}
......@@ -403,6 +403,21 @@ class FacetSetTest extends \PHPUnit_Framework_TestCase
$observer->createFacetRange($options, $add);
}
/**
* @dataProvider createFacetAddProvider
*/
public function testCreateFacetPivot($add)
{
$options = array('optionA' => 1, 'optionB' => 2);
$observer = $this->getMock('Solarium\QueryType\Select\Query\Component\FacetSet', array('createFacet'));
$observer->expects($this->once())
->method('createFacet')
->with($this->equalTo(FacetSet::FACET_PIVOT), $this->equalTo($options), $add);
$observer->createFacetPivot($options, $add);
}
public function testSetAndGetExtractFromResponse()
{
$this->facetSet->setExtractFromResponse(true);
......
......@@ -81,6 +81,11 @@ class HighlightingTest extends \PHPUnit_Framework_TestCase
'query' => 'text:myvalue',
'phraselimit' => 35,
'multivaluedseparatorchar' => '|',
'boundaryscannermaxscan' => 12,
'boundaryscannerchars' => "\t\n",
'boundaryscannertype' => 'LINE',
'boundaryscannerlanguage' => 'nl',
'boundaryscannercountry' => 'NL',
);
$this->hlt->setOptions($options);
......@@ -112,6 +117,11 @@ class HighlightingTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($options['query'], $this->hlt->getQuery());
$this->assertEquals($options['phraselimit'], $this->hlt->getPhraseLimit());
$this->assertEquals($options['multivaluedseparatorchar'], $this->hlt->getMultiValuedSeparatorChar());
$this->assertEquals($options['boundaryscannermaxscan'], $this->hlt->getBoundaryScannerMaxScan());
$this->assertEquals($options['boundaryscannerchars'], $this->hlt->getBoundaryScannerChars());
$this->assertEquals($options['boundaryscannertype'], $this->hlt->getBoundaryScannerType());
$this->assertEquals($options['boundaryscannerlanguage'], $this->hlt->getBoundaryScannerLanguage());
$this->assertEquals($options['boundaryscannercountry'], $this->hlt->getBoundaryScannerCountry());
}
public function testGetType()
......@@ -525,4 +535,59 @@ class HighlightingTest extends \PHPUnit_Framework_TestCase
);
}
public function testSetAndGetBoundaryScannerChars()
{
$value = "\n";
$this->hlt->setBoundaryScannerChars($value);
$this->assertEquals(
$value,
$this->hlt->getBoundaryScannerChars()
);
}
public function testSetAndGetBoundaryScannerMaxScan()
{
$value = 15;
$this->hlt->setBoundaryScannerMaxScan($value);
$this->assertEquals(
$value,
$this->hlt->getBoundaryScannerMaxScan()
);
}
public function testSetAndGetBoundaryScannerType()
{
$value = 'SENTENCE';
$this->hlt->setBoundaryScannerType($value);
$this->assertEquals(
$value,
$this->hlt->getBoundaryScannerType()
);
}
public function testSetAndGetBoundaryScannerCountry()
{
$value = 'DE';
$this->hlt->setBoundaryScannerCountry($value);
$this->assertEquals(
$value,
$this->hlt->getBoundaryScannerCountry()
);
}
public function testSetAndGetBoundaryScannerLanguage()
{
$value = 'fr';
$this->hlt->setBoundaryScannerLanguage($value);
$this->assertEquals(
$value,
$this->hlt->getBoundaryScannerLanguage()
);
}
}
......@@ -210,4 +210,23 @@ class SpellcheckTest extends \PHPUnit_Framework_TestCase
$this->spellCheck->getAccuracy()
);
}
public function testSetAndGetCollateParams()
{
$this->assertEquals(
$this->spellCheck,
$this->spellCheck->setCollateParam('mm', '100%')
);
$params = $this->spellCheck->getCollateParams();
$this->assertArrayHasKey(
'mm',
$params
);
$this->assertEquals(
'100%',
$params['mm']
);
}
}
......@@ -37,7 +37,7 @@ use Solarium\Core\Client\Request;
class DistributedSearchTest extends \PHPUnit_Framework_TestCase
{
public function testBuildComponent()
public function testBuildComponentWithShards()
{
$builder = new RequestBuilder;
$request = new Request();
......@@ -61,4 +61,26 @@ class DistributedSearchTest extends \PHPUnit_Framework_TestCase
);
}
public function testBuildComponentWithCollections()
{
$builder = new RequestBuilder;
$request = new Request();
$component = new Component();
$component->addCollection('collection1', 'localhost:8983/solr/collection1');
$component->addCollections(array(
'collection2' => 'localhost:8983/solr/collection2',
'collection3' => 'localhost:8983/solr/collection3'
));
$request = $builder->buildComponent($component, $request);
$this->assertEquals(
array(
'collection' => 'localhost:8983/solr/collection1,localhost:8983/solr/collection2,localhost:8983/solr/collection3',
),
$request->getParams()
);
}
}
......@@ -37,6 +37,7 @@ use Solarium\QueryType\Select\Query\Component\Facet\Field as FacetField;
use Solarium\QueryType\Select\Query\Component\Facet\Query as FacetQuery;
use Solarium\QueryType\Select\Query\Component\Facet\MultiQuery as FacetMultiQuery;
use Solarium\QueryType\Select\Query\Component\Facet\Range as FacetRange;
use Solarium\QueryType\Select\Query\Component\Facet\Pivot as FacetPivot;
class FacetSetTest extends \PHPUnit_Framework_TestCase
{
......@@ -174,6 +175,29 @@ class FacetSetTest extends \PHPUnit_Framework_TestCase
$request->getUri();
}
public function testBuildWithPivotFacet()
{
$this->component->addFacet(new FacetPivot(
array(
'key' => 'f1',
'fields' => 'cat,inStock',
'mincount' => 123
)
));
$request = $this->builder->buildComponent($this->component, $this->request);
$this->assertEquals(
null,
$request->getRawData()
);
$this->assertEquals(
'?facet=true&facet.pivot=cat,inStock&facet.pivot.mincount=123',
urldecode($request->getUri())
);
}
}
class UnknownFacet extends FacetField
......
......@@ -80,6 +80,11 @@ class HighlightingTest extends \PHPUnit_Framework_TestCase
$component->setTagPrefix('<i>');
$component->setTagPostfix('</i>');
$component->setMultiValuedSeparatorChar('|');
$component->setBoundaryScannerChars('.,');
$component->setBoundaryScannerMaxScan(16);
$component->setBoundaryScannerType($component::BOUNDARYSCANNER_TYPE_WORD);
$component->setBoundaryScannerCountry('be');
$component->setBoundaryScannerLanguage('en');
$request = $builder->buildComponent($component, $request);
......@@ -119,6 +124,11 @@ class HighlightingTest extends \PHPUnit_Framework_TestCase
'f.fieldB.hl.simple.post' => '</b>',
'f.fieldB.hl.fragmenter' => 'myFragmenter',
'f.fieldB.hl.useFastVectorHighlighter' => 'true',
'hl.bs.maxScan' => 16,
'hl.bs.chars' => '.,',
'hl.bs.type' => 'WORD',
'hl.bs.country' => 'be',
'hl.bs.language' => 'en',
),
$request->getParams()
);
......
......@@ -56,6 +56,7 @@ class SpellcheckTest extends \PHPUnit_Framework_TestCase
$component->setMaxCollationEvaluations(4);
$component->setCollateExtendedResults(true);
$component->setAccuracy(.2);
$component->setCollateParam('mm', '100%');
$request = $builder->buildComponent($component, $request);
......@@ -75,6 +76,7 @@ class SpellcheckTest extends \PHPUnit_Framework_TestCase
'spellcheck.maxCollationEvaluations' => 4,
'spellcheck.collateExtendedResults' => 'true',
'spellcheck.accuracy' => .2,
'spellcheck.collateParam.mm' => '100%',
),
$request->getParams()
);
......
......@@ -48,6 +48,7 @@ class FacetSetTest extends \PHPUnit_Framework_TestCase
$this->facetSet->createFacet('query', array('key' => 'keyB'));
$this->facetSet->createFacet('multiquery', array('key' => 'keyC', 'query' => array('keyC_A' => array('query' => 'id:1'), 'keyC_B' => array('query' => 'id:2'))));
$this->facetSet->createFacet('range', array('key' => 'keyD'));
$this->facetSet->createFacet('pivot', array('key' => 'keyE', 'fields' => 'cat,price'));
$this->query = new Query;
}
......@@ -83,14 +84,27 @@ class FacetSetTest extends \PHPUnit_Framework_TestCase
1,
)
)
)
),
'facet_pivot' => array(
'cat,price' => array(
array(
'field' => 'cat',
'value' => 'abc',
'count' => '123',
'pivot' => array(
array('field' => 'price', 'value' => 1, 'count' => 12),
array('field' => 'price', 'value' => 2, 'count' => 8),
)
)
),
),
)
);
$result = $this->parser->parse($this->query, $this->facetSet, $data);
$facets = $result->getFacets();
$this->assertEquals(array('keyA','keyB','keyC','keyD'), array_keys($facets));
$this->assertEquals(array('keyA','keyB','keyC','keyD', 'keyE'), array_keys($facets));
$this->assertEquals(
array('value1' => 12, 'value2' => 3),
......@@ -127,6 +141,11 @@ class FacetSetTest extends \PHPUnit_Framework_TestCase
$facets['keyD']->getAfter()
);
$this->assertEquals(
1,
count($facets['keyE'])
);
$this->query = new Query;
}
......@@ -161,7 +180,20 @@ class FacetSetTest extends \PHPUnit_Framework_TestCase
1,
)
)
)
),
'facet_pivot' => array(
'cat,price' => array(
array(
'field' => 'cat',
'value' => 'abc',
'count' => '123',
'pivot' => array(
array('field' => 'price', 'value' => 1, 'count' => 12),
array('field' => 'price', 'value' => 2, 'count' => 8),
)
)
),
),
)
);
......@@ -171,7 +203,7 @@ class FacetSetTest extends \PHPUnit_Framework_TestCase
$result = $this->parser->parse($this->query, $facetSet, $data);
$facets = $result->getFacets();
$this->assertEquals(array('keyA','keyB','keyC_A','keyC_B','keyD'), array_keys($facets));
$this->assertEquals(array('keyA','keyB','keyC_A','keyC_B','keyD', 'cat,price'), array_keys($facets));
$this->assertEquals(
array('value1' => 12, 'value2' => 3),
......@@ -214,6 +246,11 @@ class FacetSetTest extends \PHPUnit_Framework_TestCase
$facets['keyD']->getAfter()
);
$this->assertEquals(
1,
count($facets['cat,price'])
);
$this->query = new Query;
}
......
......@@ -194,6 +194,10 @@ class SpellcheckTest extends \PHPUnit_Framework_TestCase
'suggestion' => array (
0 => array (
'word' => 'ultrasharp',
'freq' => 2
),
1 => array (
'word' => 'ultrasharpy',
'freq' => 1
),
),
......@@ -209,6 +213,9 @@ class SpellcheckTest extends \PHPUnit_Framework_TestCase
$result = $this->parser->parse($this->query, null, $data);
$collations = $result->getCollations();
$this->assertEquals('dell ultrasharp', $collations[0]->getQuery());
$words = $result->getSuggestion(1)->getWords();
$this->assertEquals(array('word' => 'ultrasharpy', 'freq' => 1), $words[1]);
}
public function testParseNoData()
......
......@@ -33,7 +33,7 @@ namespace Solarium\Tests\QueryType\Select\ResponseParser;
use Solarium\QueryType\Select\Query\Query;
use Solarium\QueryType\Select\Result\FacetSet;
use Solarium\QueryType\Select\ResponseParser\ResponseParser;
use Solarium\QueryType\Update\Query\Document;
use Solarium\QueryType\Update\Query\Document\Document;
class ResponseParserTest extends \PHPUnit_Framework_TestCase
{
......@@ -54,7 +54,7 @@ class ResponseParserTest extends \PHPUnit_Framework_TestCase
)
);
$query = new Query(array('documentclass' => 'Solarium\QueryType\Update\Query\Document'));
$query = new Query(array('documentclass' => 'Solarium\QueryType\Update\Query\Document\Document'));
$query->getFacetSet();
$resultStub = $this->getMock('Solarium\QueryType\Select\Result\Result', array(), array(), '', false);
......@@ -132,7 +132,7 @@ class ResponseParserTest extends \PHPUnit_Framework_TestCase
)
);
$query = new Query(array('documentclass' => 'Solarium\QueryType\Update\Query\Document'));
$query = new Query(array('documentclass' => 'Solarium\QueryType\Update\Query\Document\Document'));
$query->getFacetSet();
$resultStub = $this->getMock('Solarium\QueryType\Select\Result\Result', array(), array(), '', false);
......
<?php
/**
* Copyright 2011 Bas de Nooijer. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this listof conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 HOLDER 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.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the copyright holder.
*/
namespace Solarium\Tests\QueryType\Select\Result\Facet\Pivot;
use Solarium\QueryType\Select\Result\Facet\Pivot\PivotItem;
class PivotItemTest extends \PHPUnit_Framework_TestCase
{
protected $values, $pivotItem;
public function setUp()
{
$this->values = array(
'field' => 'cat',
'value' => 'abc',
'count' => '123',
'pivot' => array(
array('field' => 'cat', 'value' => 1, 'count' => 12),
array('field' => 'cat', 'value' => 2, 'count' => 8),
)
);
$this->pivotItem = new PivotItem($this->values);
}
public function testGetField()
{
$this->assertEquals($this->values['field'], $this->pivotItem->getField());
}
public function testGetValue()
{
$this->assertEquals($this->values['value'], $this->pivotItem->getValue());
}
public function testGetCount()
{
$this->assertEquals($this->values['count'], $this->pivotItem->getCount());
}
public function testCount()
{
$this->assertEquals(count($this->values['pivot']), count($this->pivotItem));
}
}
<?php
/**
* Copyright 2011 Bas de Nooijer. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this listof conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 HOLDER 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.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the copyright holder.
*/
namespace Solarium\Tests\QueryType\Select\Result\Facet\Pivot;
use Solarium\QueryType\Select\Result\Facet\Pivot\Pivot;
use Solarium\QueryType\Select\Result\Facet\Pivot\PivotItem;
class PivotTest extends \PHPUnit_Framework_TestCase
{
protected $values, $facet;
public function setUp()
{
$this->values = array(
array('field' => 'cat', 'value' => 1, 'count' => 12),
array('field' => 'cat', 'value' => 2, 'count' => 8),
);
$this->facet = new Pivot($this->values);
}
public function testGetPivot()
{
$expected = array(
new PivotItem($this->values[0]),
new PivotItem($this->values[1]),
);
$this->assertEquals($expected, $this->facet->getPivot());
}
public function testCount()
{
$this->assertEquals(count($this->values), count($this->facet));
}
}
......@@ -40,7 +40,7 @@ class SuggestionTest extends \PHPUnit_Framework_TestCase
*/
protected $result;
protected $numFound, $startOffset, $endOffset, $originalFrequency, $word, $frequency;
protected $numFound, $startOffset, $endOffset, $originalFrequency, $words, $frequency;
public function setUp()
{
......@@ -48,11 +48,19 @@ class SuggestionTest extends \PHPUnit_Framework_TestCase
$this->startOffset = 2;
$this->endOffset = 3;
$this->originalFrequency = 4;
$this->word = 'dummyword';
$this->frequency = 5;
$this->words = array(
array(
'word' => 'dummyword',
'freq' => 5
),
array(
'word' => 'secondword',
'freq' => 1
)
);
$this->result = new Suggestion(
$this->numFound, $this->startOffset, $this->endOffset, $this->originalFrequency, $this->word, $this->frequency
$this->numFound, $this->startOffset, $this->endOffset, $this->originalFrequency, $this->words
);
}
......@@ -78,12 +86,17 @@ class SuggestionTest extends \PHPUnit_Framework_TestCase
public function testGetWord()
{
$this->assertEquals($this->word, $this->result->getWord());
$this->assertEquals($this->words[0]['word'], $this->result->getWord());
}
public function testGetFrequency()
{
$this->assertEquals($this->frequency, $this->result->getFrequency());
$this->assertEquals($this->words[0]['freq'], $this->result->getFrequency());
}
public function testGetWords()
{
$this->assertEquals($this->words, $this->result->getWords());
}
}
......@@ -32,7 +32,7 @@
namespace Solarium\Tests\QueryType\Update\Query\Command;
use Solarium\QueryType\Update\Query\Command\Add;
use Solarium\QueryType\Update\Query\Query;
use Solarium\QueryType\Update\Query\Document;
use Solarium\QueryType\Update\Query\Document\Document;
class AddTest extends \PHPUnit_Framework_TestCase
{
......
......@@ -30,11 +30,14 @@
*/
namespace Solarium\Tests\QueryType\Update\Query;
use Solarium\QueryType\Update\Query\Document;
use Solarium\QueryType\Update\Query\Document\Document;
class DocumentTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Document
*/
protected $doc;
protected $fields = array(
......@@ -48,11 +51,13 @@ class DocumentTest extends \PHPUnit_Framework_TestCase
$this->doc = new Document($this->fields);
}
public function testConstructorWithFieldsAndBoosts()
public function testConstructorWithFieldsAndBoostsAndModifiers()
{
$fields = array('id' => 1, 'name' => 'testname');
$boosts = array('name' => 2.7);
$doc = new Document($fields, $boosts);
$modifiers = array('name' => Document::MODIFIER_SET);
$doc = new Document($fields, $boosts, $modifiers);
$doc->setKey('id');
$this->assertEquals(
$fields,
......@@ -63,6 +68,11 @@ class DocumentTest extends \PHPUnit_Framework_TestCase
2.7,
$doc->getFieldBoost('name')
);
$this->assertEquals(
Document::MODIFIER_SET,
$doc->getFieldModifier('name')
);
}
public function testAddFieldNoBoost()
......@@ -118,6 +128,24 @@ class DocumentTest extends \PHPUnit_Framework_TestCase
);
}
public function testAddFieldWithModifier()
{
$this->doc->clear();
$this->doc->setKey('id', 1);
$this->doc->addField('myfield', 'myvalue', null, Document::MODIFIER_ADD);
$this->doc->addField('myfield', 'myvalue2', null, Document::MODIFIER_ADD);
$this->assertEquals(
array('id' => 1, 'myfield' => array('myvalue', 'myvalue2')),
$this->doc->getFields()
);
$this->assertEquals(
Document::MODIFIER_ADD,
$this->doc->getFieldModifier('myfield')
);
}
public function testSetField()
{
$this->doc->setField('name', 'newname');
......@@ -131,6 +159,23 @@ class DocumentTest extends \PHPUnit_Framework_TestCase
);
}
public function testSetFieldWithModifier()
{
$this->doc->clear();
$this->doc->setKey('id', 1);
$this->doc->setField('myfield', 'myvalue', null, Document::MODIFIER_ADD);
$this->assertEquals(
array('id' => 1, 'myfield' => 'myvalue'),
$this->doc->getFields()
);
$this->assertEquals(
Document::MODIFIER_ADD,
$this->doc->getFieldModifier('myfield')
);
}
public function testSetFieldWithFalsyValue()
{
$falsy_value = '';
......@@ -325,4 +370,78 @@ class DocumentTest extends \PHPUnit_Framework_TestCase
);
}
public function testSetAndGetFieldModifier()
{
$this->doc->setFieldModifier('name', Document::MODIFIER_ADD);
$this->assertEquals(
Document::MODIFIER_ADD,
$this->doc->getFieldModifier('name')
);
$this->assertEquals(
null,
$this->doc->getFieldModifier('non-existing-field')
);
}
public function testClearFieldsModifierRemoval()
{
$this->doc->setFieldModifier('name', Document::MODIFIER_ADD);
$this->doc->clear();
$this->assertEquals(
null,
$this->doc->getFieldBoost('name')
);
}
public function testSetFieldModifierWithInvalidValue()
{
$this->setExpectedException('Solarium\Exception\RuntimeException');
$this->doc->setFieldModifier('name', 'invalid_modifier_value');
}
public function testSetAndGetFieldsUsingModifiers()
{
$this->doc->clear();
$this->doc->setKey('id', 1);
$this->doc->setField('name', 'newname', null, Document::MODIFIER_SET);
$this->assertEquals(
array('id' => 1, 'name' => 'newname'),
$this->doc->getFields()
);
}
public function testSetAndGetFieldsUsingModifiersWithoutKey()
{
$this->doc->clear();
$this->doc->setField('id', 1);
$this->doc->setField('name', 'newname', null, Document::MODIFIER_SET);
$this->setExpectedException('Solarium\Exception\RuntimeException');
$this->doc->getFields();
}
public function testSetAndGetVersion()
{
$this->assertEquals(
null,
$this->doc->getVersion()
);
$this->doc->setVersion(Document::VERSION_MUST_NOT_EXIST);
$this->assertEquals(
Document::VERSION_MUST_NOT_EXIST,
$this->doc->getVersion()
);
$this->doc->setVersion(234);
$this->assertEquals(
234,
$this->doc->getVersion()
);
}
}
......@@ -34,7 +34,7 @@ use Solarium\Core\Client\Client;
use Solarium\QueryType\Update\Query\Query;
use Solarium\QueryType\Update\Query\Command\Rollback;
use Solarium\QueryType\Update\Query\Command\Commit;
use Solarium\QueryType\Update\Query\Document;
use Solarium\QueryType\Update\Query\Document\Document;
class QueryTest extends \PHPUnit_Framework_TestCase
{
......@@ -261,6 +261,22 @@ class QueryTest extends \PHPUnit_Framework_TestCase
);
}
public function testAddDeleteQueryWithBind()
{
$this->query->addDeleteQuery('id:%1%', array(678));
$commands = $this->query->getCommands();
$this->assertEquals(
Query::COMMAND_DELETE,
$commands[0]->getType()
);
$this->assertEquals(
array('id:678'),
$commands[0]->getQueries()
);
}
public function testAddDeleteQueries()
{
$this->query->addDeleteQueries(array('id:1','id:2'));
......
......@@ -38,7 +38,7 @@ use Solarium\QueryType\Update\Query\Command\Delete as DeleteCommand;
use Solarium\QueryType\Update\Query\Command\Optimize as OptimizeCommand;
use Solarium\QueryType\Update\Query\Command\Commit as CommitCommand;
use Solarium\QueryType\Update\Query\Command\Rollback as RollbackCommand;
use Solarium\QueryType\Update\Query\Document;
use Solarium\QueryType\Update\Query\Document\Document;
class RequestBuilderTest extends \PHPUnit_Framework_TestCase
{
......@@ -159,6 +159,66 @@ class RequestBuilderTest extends \PHPUnit_Framework_TestCase
);
}
public function testBuildAddXmlWithFieldModifiers()
{
$doc = new Document();
$doc->setKey('id',1);
$doc->addField('category', 123, null, Document::MODIFIER_ADD);
$doc->addField('name', 'test', 2.5, Document::MODIFIER_SET);
$doc->setField('stock', 2, null, Document::MODIFIER_INC);
$command = new AddCommand();
$command->addDocument($doc);
$this->assertEquals(
'<add><doc><field name="id">1</field><field name="category" update="add">123</field><field name="name" boost="2.5" update="set">test</field><field name="stock" update="inc">2</field></doc></add>',
$this->builder->buildAddXml($command)
);
}
public function testBuildAddXmlWithFieldModifiersAndMultivalueFields()
{
$doc = new Document();
$doc->setKey('id',1);
$doc->addField('category', 123, null, Document::MODIFIER_ADD);
$doc->addField('category', 234, null, Document::MODIFIER_ADD);
$doc->addField('name', 'test', 2.3, Document::MODIFIER_SET);
$doc->setField('stock', 2, null, Document::MODIFIER_INC);
$command = new AddCommand();
$command->addDocument($doc);
$this->assertEquals(
'<add><doc><field name="id">1</field><field name="category" update="add">123</field><field name="category" update="add">234</field><field name="name" boost="2.3" update="set">test</field><field name="stock" update="inc">2</field></doc></add>',
$this->builder->buildAddXml($command)
);
}
public function testBuildAddXmlWithVersionedDocument()
{
$doc = new Document(array('id' => 1));
$doc->setVersion(Document::VERSION_MUST_NOT_EXIST);
$command = new AddCommand;
$command->addDocument($doc);
$this->assertEquals(
'<add><doc><field name="id">1</field><field name="_version_">-1</field></doc></add>',
$this->builder->buildAddXml($command)
);
}
public function testBuildAddXmlWithDateTime()
{
$command = new AddCommand;
$command->addDocument(new Document(array('id' => 1, 'datetime' => new \DateTime('2013-01-15 14:41:58'))));
$this->assertEquals(
'<add><doc><field name="id">1</field><field name="datetime">2013-01-15T14:41:58Z</field></doc></add>',
$this->builder->buildAddXml($command, $this->query)
);
}
public function testBuildDeleteXml()
{
$command = new DeleteCommand;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment