Commit a7335438 authored by Bas de Nooijer's avatar Bas de Nooijer

Merge branch 'develop' into feature/nextgen

Conflicts:
	library/Solarium/Client.php
	library/Solarium/Core/Client/Adapter/ZendHttp.php
	library/Solarium/Core/Client/Request.php
parents b8fb5170 5e267b02
<?php <?php
/** /**
* Copyright 2011 Bas de Nooijer. All rights reserved. * Copyright 2011 Bas de Nooijer. All rights reserved.
* Copyright 2012 Alexander Brausewetter. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
...@@ -29,6 +30,7 @@ ...@@ -29,6 +30,7 @@
* policies, either expressed or implied, of the copyright holder. * policies, either expressed or implied, of the copyright holder.
* *
* @copyright Copyright 2011 Bas de Nooijer <solarium@raspberry.nl> * @copyright Copyright 2011 Bas de Nooijer <solarium@raspberry.nl>
* @copyright Copyright 2012 Alexander Brausewetter <alex@helpdeskhq.com>
* @license http://github.com/basdenooijer/solarium/raw/master/COPYING * @license http://github.com/basdenooijer/solarium/raw/master/COPYING
* @link http://www.solarium-project.org/ * @link http://www.solarium-project.org/
*/ */
...@@ -44,6 +46,8 @@ use Solarium\Core\Client\Request; ...@@ -44,6 +46,8 @@ use Solarium\Core\Client\Request;
use Solarium\Core\Client\Response; use Solarium\Core\Client\Response;
use Solarium\Core\Client\Endpoint; use Solarium\Core\Client\Endpoint;
use Solarium\Exception\HttpException; use Solarium\Exception\HttpException;
use Solarium\Exception\RuntimeException;
use Solarium\Exception\OutOfBoundsException;
/** /**
* Adapter that uses a Zend_Http_Client * Adapter that uses a Zend_Http_Client
...@@ -165,6 +169,32 @@ class ZendHttp extends Configurable implements AdapterInterface ...@@ -165,6 +169,32 @@ class ZendHttp extends Configurable implements AdapterInterface
public function execute($request, $endpoint) public function execute($request, $endpoint)
{ {
$client = $this->getZendHttp(); $client = $this->getZendHttp();
$client->resetParameters();
switch ($request->getMethod()) {
case Request::METHOD_GET:
$client->setMethod(\Zend_Http_Client::GET);
$client->setParameterGet($request->getQueryAsArray());
break;
case Request::METHOD_POST:
$client->setMethod(\Zend_Http_Client::POST);
if ($request->getFileUpload()) {
$this->prepareFileUpload($client, $request);
} else {
$client->setParameterGet($request->getQueryAsArray());
$client->setRawData($request->getRawData());
$request->addHeader('Content-Type: text/xml; charset=UTF-8');
}
break;
case Request::METHOD_HEAD:
$client->setMethod(\Zend_Http_Client::HEAD);
$client->setParameterGet($request->getQueryAsArray());
break;
default:
throw new OutOfBoundsException('Unsupported method: ' . $request->getMethod());
break;
}
$client->setMethod($request->getMethod()); $client->setMethod($request->getMethod());
$client->setUri($endpoint->getBaseUri() . $request->getUri()); $client->setUri($endpoint->getBaseUri() . $request->getUri());
...@@ -194,4 +224,55 @@ class ZendHttp extends Configurable implements AdapterInterface ...@@ -194,4 +224,55 @@ class ZendHttp extends Configurable implements AdapterInterface
return new Response($data, $headers); return new Response($data, $headers);
} }
/**
* Prepare a solarium response from the given request and client
* response
*
* @param Request $request
* @param \Zend_Http_Response $response
* @return Response
*/
protected function prepareResponse($request, $response)
{
if ($response->isError()) {
throw new HttpException(
$response->getMessage(),
$response->getStatus()
);
}
if ($request->getMethod() == Request::METHOD_HEAD) {
$data = '';
} else {
$data = $response->getBody();
}
// this is used because getHeaders doesn't return the HTTP header...
$headers = explode("\n", $response->getHeadersAsString());
return new Response($data, $headers);
}
/**
* Prepare the client to send the file and params in request
*
* @param \Zend_Http_Client $client
* @param Request $request
* @return void
*/
protected function prepareFileUpload($client, $request)
{
$filename = $request->getFileUpload();
if (($content = @file_get_contents($filename)) === false) {
throw new RuntimeException("Unable to read file '{$filename}' for upload");
}
$client->setFileUpload('content', 'content', $content, 'application/octet-stream; charset=binary');
// set query params as "multipart/form-data" fields
foreach ($request->getQueryAsArray() as $name => $value) {
$client->setFileUpload(null, $name, $value, 'text/plain; charset=utf-8');
}
}
} }
...@@ -105,6 +105,11 @@ class Client extends Configurable ...@@ -105,6 +105,11 @@ class Client extends Configurable
*/ */
const QUERY_SUGGESTER = 'suggester'; const QUERY_SUGGESTER = 'suggester';
/**
* Querytype extract
*/
const QUERY_EXTRACT = 'extract';
/** /**
* Default options * Default options
* *
...@@ -131,6 +136,7 @@ class Client extends Configurable ...@@ -131,6 +136,7 @@ class Client extends Configurable
self::QUERY_ANALYSIS_FIELD => 'Solarium\QueryType\Analysis\Query\Field', self::QUERY_ANALYSIS_FIELD => 'Solarium\QueryType\Analysis\Query\Field',
self::QUERY_TERMS => 'Solarium\QueryType\Terms\Query', self::QUERY_TERMS => 'Solarium\QueryType\Terms\Query',
self::QUERY_SUGGESTER => 'Solarium\QueryType\Suggester\Query', self::QUERY_SUGGESTER => 'Solarium\QueryType\Suggester\Query',
self::QUERY_EXTRACT => 'Solarium\QueryType\Extract\Query',
); );
/** /**
...@@ -938,6 +944,21 @@ class Client extends Configurable ...@@ -938,6 +944,21 @@ class Client extends Configurable
return $this->execute($query, $endpoint); return $this->execute($query, $endpoint);
} }
/**
* Execute an extract 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\Extract\Query $query
* @param Endpoint|string|null
* @return \Solarium\QueryType\Extract\Result\Result
*/
public function extract(QueryInterface $query, $endpoint = null)
{
return $this->execute($query, $endpoint);
}
/** /**
* Create a query instance * Create a query instance
* *
...@@ -1058,4 +1079,15 @@ class Client extends Configurable ...@@ -1058,4 +1079,15 @@ class Client extends Configurable
{ {
return $this->createQuery(self::QUERY_SUGGESTER, $options); return $this->createQuery(self::QUERY_SUGGESTER, $options);
} }
/**
* Create an extract query instance
*
* @param mixed $options
* @return \Solarium\QueryType\Extract\Query
*/
public function createExtract($options = null)
{
return $this->createExtract(self::QUERY_EXTRACT, $options);
}
} }
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
*/ */
namespace Solarium\Core\Client; namespace Solarium\Core\Client;
use Solarium\Core\Configurable; use Solarium\Core\Configurable;
use Solarium\Exception\RuntimeException;
/** /**
* Class for describing a request * Class for describing a request
...@@ -101,6 +102,9 @@ class Request extends Configurable ...@@ -101,6 +102,9 @@ class Request extends Configurable
case 'rawdata': case 'rawdata':
$this->setRawData($value); $this->setRawData($value);
break; break;
case 'file':
$this->setFileUpload($value);
break;
case 'param': case 'param':
$this->setParams($value); $this->setParams($value);
break; break;
...@@ -307,6 +311,32 @@ class Request extends Configurable ...@@ -307,6 +311,32 @@ class Request extends Configurable
return $this; return $this;
} }
/**
* Get the file to upload via "multipart/form-data" POST request
*
* @return string|null
*/
public function getFileUpload()
{
return $this->getOption('file');
}
/**
* Set the file to upload via "multipart/form-data" POST request
*
* @param string $filename Name of file to upload
* @return self
*/
public function setFileUpload($filename)
{
if (!is_file($filename) || !is_readable($filename)) {
throw new RuntimeException("Unable to read file '{$filename}' for upload");
}
$this->setOption('file', $filename);
return $this;
}
/** /**
* Get all request headers * Get all request headers
* *
...@@ -417,7 +447,8 @@ class Request extends Configurable ...@@ -417,7 +447,8 @@ class Request extends Configurable
. 'authentication: ' . print_r($this->getAuthentication(), 1) . 'authentication: ' . print_r($this->getAuthentication(), 1)
. 'resource: ' . $this->getUri() . "\n" . 'resource: ' . $this->getUri() . "\n"
. 'resource urldecoded: ' . urldecode($this->getUri()) . "\n" . 'resource urldecoded: ' . urldecode($this->getUri()) . "\n"
. 'raw data: ' . $this->getRawData() . "\n"; . 'raw data: ' . $this->getRawData() . "\n"
. 'file upload: ' . $this->getFileUpload() . "\n";
return $output; return $output;
} }
......
<?php
/**
* Copyright 2011 Bas de Nooijer. All rights reserved.
* Copyright 2012 Alexander Brausewetter. 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>
* @copyright Copyright 2012 Alexander Brausewetter <alex@helpdeskhq.com>
* @license http://github.com/basdenooijer/solarium/raw/master/COPYING
* @link http://www.solarium-project.org/
*
* @package Solarium
* @subpackage Query
*/
/**
* Extract query
*
* Sends a document extract request to Solr, i.e. upload rich document content
* such as PDF, Word or HTML, parse the file contents and add it to the index.
*
* The Solr server must have the {@link http://wiki.apache.org/solr/ExtractingRequestHandler
* ExtractingRequestHandler} enabled.
*
* @package Solarium
* @subpackage Query
*/
class Solarium_Query_Extract extends Solarium_Query
{
/**
* Default options
*
* @var array
*/
protected $_options = array(
'handler' => 'update/extract',
'resultclass' => 'Solarium_Result_Update',
);
/**
* Field name mappings
*
* @var array
*/
protected $_fieldMappings = array();
/**
* Get type for this query
*
* @return string
*/
public function getType()
{
return Solarium_Client::QUERYTYPE_EXTRACT;
}
/**
* Initialize options
*
* Several options need some extra checks or setup work, for these options
* the setters are called.
*
* @return void
*/
protected function _init()
{
if (isset($this->_options['fmap'])) {
$this->setFieldMappings($this->_options['fmap']);
}
}
// {{{ Options
/**
* Set the document with literal fields and boost settings
*
* The fields in the document are indexed together with the generated
* fields that Solr extracts from the file.
*
* @param Solarium_Document_ReadWrite $document
* @return Solarium_Query_Extract
*/
public function setDocument($document)
{
return $this->_setOption('document', $document);
}
/**
* Get the document with literal fields and boost settings
*
* @return Solarium_Document_ReadWrite|null
*/
public function getDocument()
{
return $this->getOption('document');
}
/**
* Set the file to upload and index
*
* @param string $filename
* @return Solarium_Query_Extract
*/
public function setFile($filename)
{
return $this->_setOption('file', $filename);
}
/**
* Get the file to upload and index
*
* @return string|null
*/
public function getFile()
{
return $this->getOption('file');
}
/**
* Set the prefix for fields that are not defined in the schema
*
* @param string $uprefix
* @return Solarium_Query_Extract
*/
public function setUprefix($uprefix)
{
return $this->_setOption('uprefix', $uprefix);
}
/**
* Get the prefix for fields that are not defined in the schema
*
* @return string|null
*/
public function getUprefix()
{
return $this->getOption('uprefix');
}
/**
* Set the field to use if uprefix is not specified and a field cannot be
* determined
*
* @param string $defaultField
* @return Solarium_Query_Extract
*/
public function setDefaultField($defaultField)
{
return $this->_setOption('defaultField', $defaultField);
}
/**
* Get the field to use if uprefix is not specified and a field cannot be
* determined
*
* @return string|null
*/
public function getDefaultField()
{
return $this->getOption('defaultField');
}
/**
* Set if all field names should be mapped to lowercase with underscores.
* For example, Content-Type would be mapped to content_type.
*
* @param bool $lowerNames
* @return Solarium_Query_Extract
*/
public function setLowernames($lowerNames)
{
return $this->_setOption('lowernames', (bool) $lowerNames);
}
/**
* Get if all field names should be mapped to lowercase with underscores
*
* @return bool
*/
public function getLowernames()
{
return $this->getOption('lowernames');
}
/**
* Set if the extract should be committed immediately
*
* @param bool $commit
* @return Solarium_Query_Extract Provides fluent interface
*/
public function setCommit($commit)
{
return $this->_setOption('commit', (bool) $commit);
}
/**
* Get if the extract should be committed immediately
*
* @return bool
*/
public function getCommit()
{
return $this->getOption('commit');
}
/**
* Set milliseconds until extract update is committed. Since Solr 3.4
*
* @param int $commitWithin
* @return Solarium_Query_Extract Provides fluent interface
*/
public function setCommitWithin($commitWithin)
{
return $this->_setOption('commitWithin', $commitWithin);
}
/**
* Get milliseconds until extract update is committed. Since Solr 3.4
*
* @return int
*/
public function getCommitWithin()
{
return $this->getOption('commitWithin');
}
// }}}
// {{{ Field Mappings
/**
* Add a name mapping from one field to another
*
* Example: fmap.content=text will cause the content field normally
* generated by Tika to be moved to the "text" field.
*
* @param string $fromField Original field name
* @param mixed|array $toField New field name
* @return Solarium_Query_Extract Provides fluent interface
*/
public function addFieldMapping($fromField, $toField)
{
$this->_fieldMappings[$fromField] = $toField;
return $this;
}
/**
* Add multiple field name mappings
*
* @param array $mappings Name mapping in the form [$fromField => $toField, ...]
* @return Solarium_Query_Extract Provides fluent interface
*/
public function addFieldMappings($mappings)
{
foreach ($mappings AS $fromField => $toField) {
$this->addFieldMapping($fromField, $toField);
}
return $this;
}
/**
* Remove a field name mapping
*
* @param string $fromField
* @return Solarium_Query_Extract Provides fluent interface
*/
public function removeFieldMapping($fromField)
{
if (isset($this->_fieldMappings[$fromField])) {
unset($this->_fieldMappings[$fromField]);
}
return $this;
}
/**
* Remove all field name mappings
*
* @return Solarium_Query_Extract Provides fluent interface
*/
public function clearFieldMappings()
{
$this->_fieldMappings = array();
return $this;
}
/**
* Get all field name mappings
*
* @return array
*/
public function getFieldMappings()
{
return $this->_fieldMappings;
}
/**
* Set many field name mappings. This overwrites any existing fields.
*
* @param array $mappings Name mapping in the form [$fromField => $toField, ...]
* @return Solarium_Query_Extract Provides fluent interface
*/
public function setFieldMappings($mappings)
{
$this->clearFieldMappings();
$this->addFieldMappings($mappings);
return $this;
}
// }}}
}
<?php
/**
* Copyright 2011 Bas de Nooijer. All rights reserved.
* Copyright 2012 Alexander Brausewetter. 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>
* @copyright Copyright 2012 Alexander Brausewetter <alex@helpdeskhq.com>
* @license http://github.com/basdenooijer/solarium/raw/master/COPYING
* @link http://www.solarium-project.org/
*
* @package Solarium
* @subpackage Client
*/
/**
* Build an extract request
*
* @package Solarium
* @subpackage Client
*/
class Solarium_Client_RequestBuilder_Extract extends Solarium_Client_RequestBuilder
{
/**
* Build the request
*
* @param Solarium_Query_Extract $query
* @return Solarium_Client_Request
*/
public function build($query)
{
$request = parent::build($query);
$request->setMethod(Solarium_Client_Request::METHOD_POST);
// common options
$request->addParam('commit', $query->getCommit());
$request->addParam('commitWithin', $query->getCommitWithin());
$request->addParam('uprefix', $query->getUprefix());
$request->addParam('lowernames', $query->getLowernames());
$request->addParam('defaultField', $query->getDefaultField());
foreach ($query->getFieldMappings() AS $fromField => $toField) {
$request->addParam('fmap.' . $fromField, $toField);
}
// document
if (($doc = $query->getDocument()) != null) {
if ($doc->getBoost() !== null) {
throw new Solarium_Exception('Extract does not support document-level boosts, use field boosts instead.');
}
// literal.*
foreach ($doc->getFields() AS $name => $value) {
$value = (array) $value;
foreach ($value AS $multival) {
$request->addParam('literal.' . $name, $multival);
}
}
// boost.*
foreach ($doc->getFieldBoosts() AS $name => $value) {
$request->addParam('boost.' . $name, $value);
}
}
// file
$request->setFileUpload($query->getFile());
$request->addParam('resource.name', basename($query->getFile()));
return $request;
}
}
...@@ -183,6 +183,16 @@ class Document extends AbstractDocument implements DocumentInterface ...@@ -183,6 +183,16 @@ class Document extends AbstractDocument implements DocumentInterface
return $this; return $this;
} }
/**
* Get boost values for all fields
*
* @return array
*/
public function getFieldBoosts()
{
return $this->fieldBoosts;
}
/** /**
* Set the document boost value * Set the document boost value
* *
......
...@@ -49,6 +49,6 @@ interface DocumentInterface ...@@ -49,6 +49,6 @@ interface DocumentInterface
* *
* @param array $fields * @param array $fields
*/ */
public function __construct(array $fields, array $boosts); public function __construct(array $fields = array(), array $boosts = array());
} }
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