Commit 2a98c07a authored by Bas de Nooijer's avatar Bas de Nooijer

Merge branch 'release/3.0.0'

parents 5c7afe1c 18c31bf7
.idea
build
phpunit.xml
composer.phar
composer.lock
vendor
\ No newline at end of file
language: php
phps:
- 5.4
- 5.3
script: phpunit -c phpunit.xml.dist
before_script:
- wget http://getcomposer.org/composer.phar
- php composer.phar install
script: phpunit -c phpunit.xml.travis
# Solarium PHP Solr client library
Solarium is a PHP Solr client that not only facilitates Solr communication but
also tries to accurately model Solr concepts.
## What is Solarium?
Solarium is a PHP Solr client library that accurately model Solr concepts. Where many other Solr libraries only handle
the communication with Solr, Solarium also relieves you of handling all the complex Solr query parameters using a
well documented API.
Please see the project website for a more detailed description.
## Project website
http://www.solarium-project.org/
## Requirements
Solarium only supports PHP 5.3 and up.
It's highly recommended to have Curl enabled in your PHP environment. However if you don't have Curl available you can
switch from using Curl (the default) to another client adapter. The other adapters don't support all the features of the
Curl adapter.
## Getting started
The preferred way to install Solarium is by using Composer. Solarium is available on Packagist.
For more info see
http://wiki.solarium-project.org/index.php/V3:Installation#Getting_Solarium
## More information
* Manual
http://wiki.solarium-project.org/index.php/Solarium_3.x_manual
* Project website
http://www.solarium-project.org/
## License:
See the COPYING file or view online
https://github.com/basdenooijer/solarium/blob/master/COPYING
* API docs
http://api.solarium-project.org/
## Issue tracker
http://github.com/basdenooijer/solarium/issues
* Issue tracker
http://github.com/basdenooijer/solarium/issues
## Contributors
https://github.com/basdenooijer/solarium/contributors
* Contributors
https://github.com/basdenooijer/solarium/contributors
## API docs
http://api.solarium-project.org/
* License
See the COPYING file or view online:
https://github.com/basdenooijer/solarium/blob/master/COPYING
## Travis Continuous Integration status
......
......@@ -57,7 +57,7 @@ you could also write the switches here)
<!-- Generate checkstyle.xml -->
<target name="phpcs">
<exec executable="phpcs" output="/dev/null">
<arg line="--report=checkstyle --report-file=${basedir}/build/logs/checkstyle.xml --standard=Zend library" />
<arg line="--report=checkstyle --report-file=${basedir}/build/logs/checkstyle.xml --standard=Symfony2 library" />
</exec>
</target>
......
......@@ -4,7 +4,6 @@
"description": "PHP Solr client",
"keywords": ["solr", "search", "php"],
"homepage": "http://www.solarium-project.org",
"version": "2.4.0",
"license": "NewBSD",
"authors": [
{
......@@ -13,9 +12,15 @@
}
],
"require": {
"php": ">=5.2.0"
"php": ">=5.3.2",
"symfony/event-dispatcher": "2.1.4"
},
"autoload": {
"psr-0": { "Solarium": "library/" }
},
"extra": {
"branch-alias": {
"dev-develop": "3.0-dev"
}
}
}
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// check solarium version available
echo 'Solarium library version: ' . Solarium_Version::VERSION . ' - ';
echo 'Solarium library version: ' . Solarium\Client::VERSION . ' - ';
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// create a ping query
$ping = $client->createPing();
......@@ -18,7 +18,7 @@ try{
echo 'Ping query successful';
echo '<br/><pre>';
var_dump($result->getData());
}catch(Solarium_Exception $e){
}catch(Solarium\Exception $e){
echo 'Ping query failed';
}
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
$query = $client->createQuery($client::QUERY_SELECT);
// this executes the query and returns the result
$resultset = $client->select($query);
$resultset = $client->execute($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
if ($_POST) {
// if data is posted add it to solr
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get an update query instance
$update = $client->createUpdate();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
......@@ -19,7 +20,7 @@ $query->setStart(2)->setRows(20);
$query->setFields(array('id','name','price'));
// sort the results by price ascending
$query->addSort('price', Solarium_Query_Select::SORT_ASC);
$query->addSort('price', $query::SORT_ASC);
// this executes the query and returns the result
$resultset = $client->select($query);
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// this is the custom result document class
class myDoc extends Solarium_Document_ReadOnly{
class myDoc extends Solarium\QueryType\Select\Result\Document{
public function getSpecialPrice()
{
......@@ -16,7 +16,7 @@ class myDoc extends Solarium_Document_ReadOnly{
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
// get the dismax component and set a boost query
$dismax = $query->getDisMax();
// override the default setting of 'dismax' to enable 'edismax'
$dismax->setQueryParser('edismax');
$edismax = $query->getEDisMax();
// this query is now a dismax query
$query->setQuery('memory -printer');
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
......@@ -22,7 +22,6 @@ $spellcheck->setCollateExtendedResults(true);
$resultset = $client->select($query);
$spellcheckResult = $resultset->getSpellcheck();
echo '<h1>Correctly spelled?</h1>';
if ($spellcheckResult->getCorrectlySpelled()) {
echo 'yes';
......@@ -41,10 +40,13 @@ foreach($spellcheckResult as $suggestion) {
echo '<hr/>';
}
$collation = $spellcheckResult->getCollation();
echo '<h1>Collation</h1>';
echo 'Query: '.$collation->getQuery().'<br/>';
echo 'Hits: '.$collation->getHits().'<br/>';
$collations = $spellcheckResult->getCollations();
echo '<h1>Collations</h1>';
foreach($collations as $collation) {
echo 'Query: '.$collation->getQuery().'<br/>';
echo 'Hits: '.$collation->getHits().'<br/>';
echo '<hr/>';
}
echo 'Corrections:<br/>';
foreach($collation->getCorrections() as $input => $correction) {
echo $input . ' => ' . $correction .'<br/>';
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance and a query helper instance
$query = $client->createSelect();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
use Solarium\Client;
use Solarium\QueryType\Select\Query\Query as Select;
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Client($config);
// first create a base query as a query class
class PriceQuery extends Solarium_Query_Select
class PriceQuery extends Select
{
protected function _init()
protected function init()
{
parent::init();
// set a query (all prices starting from 12)
$this->setQuery('price:[12 TO *]');
......@@ -37,10 +42,10 @@ if(isset($_GET['start']) && is_numeric($_GET['start'])){
// in this example this class isn't actually used, but you can simple replace
// the var $query with an instance of this class...
class LowerPriceQuery extends PriceQuery{
protected function _init()
protected function init()
{
// this call makes sure we get all the settings of the parent class
parent::_init();
parent::init();
$this->setQuery('price:[5 TO *]');
}
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get an update query instance
$update = $client->createUpdate();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get an update query instance
$update = $client->createUpdate();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get an update query instance
$update = $client->createUpdate();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get an update query instance
$update = $client->createUpdate();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get an update query instance
$update = $client->createUpdate();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
use Solarium\Client;
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Client($config);
// get a morelikethis query instance
$query = $client->createMoreLikeThis();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a morelikethis query instance
$query = $client->createMoreLikeThis();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get an analysis document query
$query = $client->createAnalysisDocument();
......@@ -12,7 +12,7 @@ $query = $client->createAnalysisDocument();
$query->setShowMatch(true);
$query->setQuery('ipod');
$doc = new Solarium_Document_ReadWrite(
$doc = new Solarium\QueryType\Update\Query\Document(
array(
'id' => 'MA147LL',
'name' => 'Apple 60 GB iPod with Video Playback Black',
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get an analysis document query
$query = $client->createAnalysisField();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a terms query instance
$query = $client->createTerms();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a suggester query instance
$query = $client->createSuggester();
......
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get an extract query instance and add settings
$query = $client->createExtract();
$query->addFieldMapping('content', 'text');
$query->setUprefix('attr_');
$query->setFile(__DIR__.'/index.html');
$query->setCommit(true);
$query->setOmitHeader(false);
// add document
$doc = $query->createDocument();
$doc->id = 'extract-test';
$doc->some = 'more fields';
$query->setDocument($doc);
// this executes the query and returns the result
$result = $client->extract($query);
echo '<b>Extract query executed</b><br/>';
echo 'Query status: ' . $result->getStatus(). '<br/>';
echo 'Query time: ' . $result->getQueryTime();
htmlFooter();
\ No newline at end of file
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
......@@ -13,7 +14,7 @@ $query = $client->createSelect();
$query->setQuery('*:*');
$query->setStart(2)->setRows(20);
$query->setFields(array('id','name','price'));
$query->addSort('price', Solarium_Query_Select::SORT_ASC);
$query->addSort('price', $query::SORT_ASC);
// create a filterquery using the API
$fq = $query->createFilterQuery('maxprice')->setQuery('price:[1 TO 300]');
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
......@@ -29,7 +29,7 @@ $select = array(
);
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance based on the config
$query = $client->createSelect($select);
......
<?php
require('init.php');
require(__DIR__.'/init.php');
use Solarium\Client;
use Solarium\QueryType\Select\Query\Query as Select;
htmlHeader();
// In most cases using the API or config is advisable, however in some cases it can make sense to extend classes.
// This makes it possible to create 'query inheritance' like in this example
class ProductQuery extends Solarium_Query_Select{
class ProductQuery extends Select{
protected function _init()
protected function init()
{
parent::_init();
parent::init();
// basic params
$this->setQuery('*:*');
$this->setStart(2)->setRows(20);
$this->setFields(array('id','name','price'));
$this->addSort('price', Solarium_Query_Select::SORT_ASC);
$this->addSort('price', self::SORT_ASC);
// create a facet field instance and set options
$facetSet = $this->getFacetSet();
......@@ -24,13 +27,13 @@ class ProductQuery extends Solarium_Query_Select{
}
// This query inherits all of the query params of it's parent (using parent::_init) and adds some more
// This query inherits all of the query params of its parent (using parent::init) and adds some more
// Ofcourse it could also alter or remove settings
class ProductPriceLimitedQuery extends ProductQuery{
protected function _init()
protected function init()
{
parent::_init();
parent::init();
// create a filterquery
$this->createFilterQuery('maxprice')->setQuery('price:[1 TO 300]');
......@@ -39,7 +42,7 @@ class ProductPriceLimitedQuery extends ProductQuery{
}
// create a client instance
$client = new Solarium_Client($config);
$client = new Client($config);
// create a query instance
$query = new ProductPriceLimitedQuery;
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// This example shows how to manually execute the query flow.
......@@ -10,7 +10,7 @@ htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// create a select query instance
$query = $client->createSelect();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
use Solarium\Client;
use Solarium\QueryType\Select\Query\Query as Select;
htmlHeader();
// This is a custom query class that could have some customized logic
class MyQuery extends Solarium_Query_Select
class MyQuery extends Select
{
// ...customization here...
}
......@@ -12,26 +15,16 @@ class MyQuery extends Solarium_Query_Select
// And this is the extended client, that modifies the default query mapping
// for select queries to our custom query class.
// BTW, the same could also be done using a plugin, see example 5.3.2
class MyClient extends Solarium_Client
class MyClient extends Client
{
/**
* Querytype mappings
*/
protected $_queryTypes = array(
self::QUERYTYPE_SELECT => array(
self::QUERY_SELECT => array(
'query' => 'MyQuery',
'requestbuilder' => 'Solarium_Client_RequestBuilder_Select',
'responseparser' => 'Solarium_Client_ResponseParser_Select'
),
self::QUERYTYPE_UPDATE => array(
'query' => 'Solarium_Query_Update',
'requestbuilder' => 'Solarium_Client_RequestBuilder_Update',
'responseparser' => 'Solarium_Client_ResponseParser_Update'
),
self::QUERYTYPE_PING => array(
'query' => 'Solarium_Query_Ping',
'requestbuilder' => 'Solarium_Client_RequestBuilder_Ping',
'responseparser' => 'Solarium_Client_ResponseParser_Ping'
'requestbuilder' => 'Solarium\QueryType\Select\RequestBuilder\RequestBuilder',
'responseparser' => 'Solarium\QueryType\Select\ResponseParser\ResponseParser'
),
);
}
......
<?php
require('init.php');
require(__DIR__.'/init.php');
use Solarium\Core\Event\Events;
// this very simple plugin shows a timing for each event and display some request debug info
class basicDebug extends Solarium_Plugin_Abstract
class basicDebug extends Solarium\Core\Plugin\Plugin
{
protected $_start;
protected $_output = array();
protected $start;
protected $output = array();
public function _initPlugin()
protected function initPluginType()
{
$this->_start = microtime(true);
$this->start = microtime(true);
$dispatcher = $this->client->getEventDispatcher();
$dispatcher->addListener(Events::PRE_CREATE_REQUEST, array($this, 'preCreateRequest'));
$dispatcher->addListener(Events::POST_CREATE_REQUEST, array($this, 'postCreateRequest'));
$dispatcher->addListener(Events::PRE_EXECUTE_REQUEST, array($this, 'preExecuteRequest'));
$dispatcher->addListener(Events::POST_EXECUTE_REQUEST, array($this, 'postExecuteRequest'));
$dispatcher->addListener(Events::PRE_CREATE_RESULT, array($this, 'preCreateResult'));
$dispatcher->addListener(Events::POST_CREATE_RESULT, array($this, 'postCreateResult'));
$dispatcher->addListener(Events::PRE_EXECUTE, array($this, 'preExecute'));
$dispatcher->addListener(Events::POST_EXECUTE, array($this, 'postExecute'));
$dispatcher->addListener(Events::PRE_CREATE_QUERY, array($this, 'preCreateQuery'));
$dispatcher->addListener(Events::POST_CREATE_QUERY, array($this, 'postCreateQuery'));
}
protected function _timer($event)
protected function timer($event)
{
$time = round(microtime(true) - $this->_start, 5);
$this->_output[] = '['.$time.'] ' . $event;
$time = round(microtime(true) - $this->start, 5);
$this->output[] = '['.$time.'] ' . $event;
}
public function display()
{
echo implode('<br/>', $this->_output);
echo implode('<br/>', $this->output);
}
public function preCreateRequest()
{
$this->_timer('preCreateRequest');
$this->timer('preCreateRequest');
}
public function postCreateRequest()
{
$this->_timer('postCreateRequest');
$this->timer('postCreateRequest');
}
// This method uses the aviable param(s) (see plugin abstract class)
// You can access or modify data this way
public function preExecuteRequest($request)
public function preExecuteRequest($event)
{
$this->_timer('preExecuteRequest');
$this->timer('preExecuteRequest');
// this dummy param will be visible in the debug output but will also be used in the actual Solr request
$request->addParam('dummyparam', 'dummyvalue');
$event->getRequest()->addParam('dummyparam', 'dummyvalue');
$this->_output[] = 'Request URI: ' . $request->getUri();
$this->output[] = 'Request URI: ' . $event->getRequest()->getUri();
}
public function postExecuteRequest()
{
$this->_timer('postExecuteRequest');
$this->timer('postExecuteRequest');
}
public function preCreateResult()
{
$this->_timer('preCreateResult');
$this->timer('preCreateResult');
}
public function postCreateResult()
{
$this->_timer('postCreateResult');
$this->timer('postCreateResult');
}
public function preExecute()
{
$this->_timer('preExecute');
$this->timer('preExecute');
}
public function postExecute()
{
$this->_timer('postExecute');
$this->timer('postExecute');
}
public function preCreateQuery()
{
$this->_timer('preCreateResult');
$this->timer('preCreateResult');
}
public function postCreateQuery()
{
$this->_timer('postCreateResult');
$this->timer('postCreateResult');
}
}
......@@ -90,7 +101,7 @@ htmlHeader();
// create a client instance and register the plugin
$plugin = new basicDebug();
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
$client->registerPlugin('debugger', $plugin);
// execute a select query and display the results
......
<?php
require('init.php');
require(__DIR__.'/init.php');
use Solarium\Client;
use Solarium\Core\Plugin\Plugin;
use Solarium\QueryType\Select\Query\Query as Select;
// This is a custom query class that could have some customized logic
class MyQuery extends Solarium_Query_Select
class MyQuery extends Select
{
// ...customization here...
}
// this very simple plugin that modifies the default querytype mapping
class queryCustomizer extends Solarium_Plugin_Abstract
class queryCustomizer extends Plugin
{
protected function _initPlugin()
public function initPlugin($client, $options)
{
$this->_client->registerQueryType(
Solarium_Client::QUERYTYPE_SELECT,
$client->registerQueryType(
Client::QUERY_SELECT,
'MyQuery',
'Solarium_Client_RequestBuilder_Select',
'Solarium_Client_ResponseParser_Select'
'Solarium\QueryType\Select\RequestBuilder\RequestBuilder',
'Solarium\QueryType\Select\ResponseParser\ResponseParser'
);
}
......@@ -27,7 +30,7 @@ class queryCustomizer extends Solarium_Plugin_Abstract
htmlHeader();
// create a client instance and register the plugin
$client = new Solarium_Client($config);
$client = new Client($config);
$client->registerPlugin('querycustomizer', 'queryCustomizer');
// create a select query instance
......
......@@ -3,14 +3,14 @@
require_once 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// set the adapter to zendhttp and get a zendhttp client instance reference
$client->setAdapter('Solarium_Client_Adapter_ZendHttp');
$client->setAdapter('Solarium\Core\Client\Adapter\ZendHttp');
$zendHttp = $client->getAdapter()->getZendHttp();
// you can use any of the zend_http features, like http-authentication
......
......@@ -3,14 +3,14 @@
require_once 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// set the adapter to peclhttp
$client->setAdapter('Solarium_Client_Adapter_PeclHttp');
$client->setAdapter('Solarium\Core\Client\Adapter\PeclHttp');
// get a select query instance
$query = $client->createSelect();
......
......@@ -3,14 +3,16 @@
require_once 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// set the adapter to curl
$client->setAdapter('Solarium_Client_Adapter_Curl');
// note that this is only shown for documentation purposes, normally you don't need
// to do this as curl is the default adapter
$client->setAdapter('Solarium\Core\Client\Adapter\Curl');
// get a select query instance
$query = $client->createSelect();
......
<?php
require_once 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// set the adapter to curl
$client->setAdapter('Solarium\Core\Client\Adapter\Http');
// get a select query instance
$query = $client->createSelect();
// 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();
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach($document AS $field => $value)
{
// this converts multivalue fields to a comma-separated string
if(is_array($value)) $value = implode(', ', $value);
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
htmlFooter();
\ No newline at end of file
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance and get a select query instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance and get loadbalancer plugin instance
$client = new Solarium_Client($config);
$loadbalancer = $client->getPlugin('loadbalancer');
// create a client instance and create endpoints
$client = new Solarium\Client($config);
$endpoint1 = $client->createEndpoint('local1'); //normally you would add endpoint specific settings...
$endpoint2 = $client->createEndpoint('local2');
$endpoint3 = $client->createEndpoint('local3');
// apply loadbalancer settings
$optionsSolrOne = array('host' => '127.0.0.1', 'port' => 8983);
$optionsSolrTwo = array('host' => '127.0.0.1', 'port' => 7574);
$loadbalancer->addServer('solr1', $optionsSolrOne, 100);
$loadbalancer->addServer('solr2', $optionsSolrTwo, 200);
$loadbalancer->addServer('solr3', $optionsSolrTwo, 1);
// get loadbalancer plugin instance and add endpoints
$loadbalancer = $client->getPlugin('loadbalancer');
$loadbalancer->addEndpoint($endpoint1, 100);
$loadbalancer->addEndpoint($endpoint2, 100);
$loadbalancer->addEndpoint($endpoint3, 1);
// create a basic query to execute
$query = $client->createSelect();
......@@ -22,26 +23,27 @@ for($i=1; $i<=8; $i++) {
$resultset = $client->select($query);
echo 'Query execution #' . $i . '<br/>';
echo 'NumFound: ' . $resultset->getNumFound(). '<br/>';
echo 'Server: ' . $loadbalancer->getLastServerKey() .'<hr/>';
echo 'Server: ' . $loadbalancer->getLastEndpoint() .'<hr/>';
}
// force a server for a query (normally solr 3 is extremely unlikely based on it's weight)
$loadbalancer->setForcedServerForNextQuery('solr3');
// force a server for a query (normally solr 3 is extremely unlikely based on its weight)
$loadbalancer->setForcedEndpointForNextQuery('local3');
$resultset = $client->select($query);
echo 'Query execution with server forced to solr3<br/>';
echo 'Query execution with server forced to local3<br/>';
echo 'NumFound: ' . $resultset->getNumFound(). '<br/>';
echo 'Server: ' . $loadbalancer->getLastServerKey() .'<hr/>';
echo 'Server: ' . $loadbalancer->getLastEndpoint() .'<hr/>';
// test a ping query
$query = $client->createPing();
$client->ping($query);
echo 'Loadbalanced ping query, should display a loadbalancing server:<br/>';
echo 'Ping server: ' . $loadbalancer->getLastServerKey() .'<hr/>';
echo 'Ping server: ' . $loadbalancer->getLastEndpoint() .'<hr/>';
// exclude ping query from loadbalancing
$loadbalancer->addBlockedQueryType(Solarium_Client::QUERYTYPE_PING);
$loadbalancer->addBlockedQueryType(Solarium\Client::QUERY_PING);
$client->ping($query);
echo 'Non-loadbalanced ping query, should not display a loadbalancing server:<br/>';
echo 'Ping server: ' . $loadbalancer->getLastServerKey() .'<hr/>';
echo 'Ping server: ' . $loadbalancer->getLastEndpoint() .'<hr/>';
htmlFooter();
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance and autoload the postbigrequest plugin
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
$client->getPlugin('postbigrequest');
// create a basic query to execute
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance and autoload the customize request plugin
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
$customizer = $client->getPlugin('customizerequest');
// add a persistent HTTP header (using array input values)
......
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance and autoload the customize request plugin
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
$parallel = $client->getPlugin('parallelexecution');
// Add a delay param to better show the effect, as an example Solr install with
......
<?php
require('init.php');
require(__DIR__.'/init.php');
// this very simple plugin is used to show some events
class simpleDebug extends Solarium_Plugin_Abstract
{
protected $_output = array();
public function display()
{
echo implode('<br/>', $this->_output);
}
public function eventBufferedAddFlushStart($buffer) {
$this->_output[] = 'Flushing buffer (' . count($buffer) . 'docs)';
}
}
use Solarium\Plugin\BufferedAdd\Event\Events;
use Solarium\Plugin\BufferedAdd\Event\PreFlush as PreFlushEvent;
htmlHeader();
// create a client instance and autoload the buffered add plugin
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
$buffer = $client->getPlugin('bufferedadd');
$buffer->setBufferSize(10); // this is quite low, in most cases you can use a much higher value
// also register a plugin for outputting events
$debug = new simpleDebug();
$client->registerPlugin('debugger', $debug);
// also register an event hook to display what is happening
$client->getEventDispatcher()->addListener(
Events::PRE_FLUSH,
function(PreFlushEvent $event){
echo 'Flushing buffer (' . count($event->getBuffer()) . 'docs)<br/>';
}
);
// let's insert 25 docs
for ($i=1; $i<=25; $i++) {
......@@ -45,7 +37,6 @@ for ($i=1; $i<=25; $i++) {
// manually flush the remainder. Alternatively you can use the commit method if you want to include a commit command.
$buffer->flush();
// In total 3 flushes (requests) have been sent to Solr. This should be visible in this output:
$debug->display();
// In total 3 flushes (requests) have been sent to Solr. This should be visible in the output of the event hook.
htmlFooter();
\ No newline at end of file
<?php
require('init.php');
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium_Client($config);
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
......
<?php
require('../library/Solarium/Autoloader.php');
Solarium_Autoloader::register();
\ No newline at end of file
<?php
$config = array(
'adapteroptions' => array(
'endpoint' => array(
'localhost' => array(
'host' => '127.0.0.1',
'port' => 8983,
'path' => '/solr/',
)
)
);
......@@ -85,6 +85,7 @@
<li><a href="2.5-terms-query.php">2.5 Terms query</a></li>
<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>
</ul>
<li>4. Usage modes</li>
......@@ -112,6 +113,7 @@
<li><a href="6.1.1-zend-http-adapter.php">6.1.1 Zend_Http adapter</a></li>
<li><a href="6.1.2-pecl-http-adapter.php">6.1.2 Pecl_Http adapter</a></li>
<li><a href="6.1.3-curl-adapter.php">6.1.3 Curl adapter</a></li>
<li><a href="6.1.4-http-adapter.php">6.1.4 Http adapter (PHP stream)</a></li>
</ul>
<li><a href="6.2-escaping.php">6.2 Escaping</a></li>
<li><a href="6.3-placeholder-syntax.php">6.3 Placeholder syntax</a></li>
......
......@@ -3,7 +3,7 @@
error_reporting(E_ALL);
ini_set('display_errors', true);
require('autoload.php');
require __DIR__.'/../vendor/autoload.php';
if (file_exists('config.php')) {
require('config.php');
......
......@@ -31,20 +31,25 @@
* @copyright Copyright 2011 Bas de Nooijer <solarium@raspberry.nl>
* @license http://github.com/basdenooijer/solarium/raw/master/COPYING
* @link http://www.solarium-project.org/
*
* @package Solarium
*/
/**
* @namespace
*/
namespace Solarium;
/**
* Autoloader
*
* This class is included to allow for easy usage of Solarium. If you already
* have your own autoloader that follows the Zend Framework class/file naming
* you can use that to autoload Solarium (for instance Zend_Loader).
* This class is included to allow for easy usage of Solarium in environments missing a PSR-O autoloader.
*
* It's recommended to install Solarium using composer, which will also provide autoloading for you. In that
* case you don't need to use this autoloader.
*
* @package Solarium
* Solarium is PSR-0 compliant, so you can also use any other compatible autoloader
* (most modern frameworks include one)
*/
class Solarium_Autoloader
class Autoloader
{
/**
......@@ -59,7 +64,7 @@ class Solarium_Autoloader
* @static
* @return void
*/
static public function register()
public static function register()
{
spl_autoload_register(array(new self, 'load'));
}
......@@ -74,17 +79,17 @@ class Solarium_Autoloader
* @param string $class
* @return void
*/
static public function load($class)
public static function load($class)
{
if (substr($class, 0, 8) == 'Solarium') {
$class = str_replace(
array('Solarium', '_'),
array('Solarium', '\\'),
array('', '/'),
$class
);
$file = dirname(__FILE__) . '/' . $class . '.php';
$file = dirname(__FILE__) . $class . '.php';
require($file);
}
......
This diff is collapsed.
<?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\Core\Client\Adapter;
use Solarium\Core\ConfigurableInterface;
use Solarium\Core\Client\Request;
use Solarium\Core\Client\Response;
use Solarium\Core\Client\Endpoint;
/**
* Interface for client adapters
*
* The goal of an adapter is to accept a query, execute it and return the right
* result object. This is actually quite a complex task as it involves the
* handling of all Solr communication.
*
* The adapter structure allows for varying implementations of this task.
*
* Most adapters will use some sort of HTTP client. In that case the
* query request builders and query response parsers can be used to simplify
* HTTP communication.
*
* However an adapter may also implement all logic by itself if needed.
*/
interface AdapterInterface extends ConfigurableInterface
{
/**
* Execute a request
*
* @param Request $request
* @param Endpoint $endpoint
* @return Response
*/
public function execute($request, $endpoint);
}
......@@ -31,58 +31,69 @@
* @copyright Copyright 2011 Bas de Nooijer <solarium@raspberry.nl>
* @license http://github.com/basdenooijer/solarium/raw/master/COPYING
* @link http://www.solarium-project.org/
*
* @package Solarium
* @subpackage Client
*/
/**
* @namespace
*/
namespace Solarium\Core\Client\Adapter;
use Solarium\Core\Configurable;
use Solarium\Core\Client\Request;
use Solarium\Core\Client\Response;
use Solarium\Core\Client\Endpoint;
use Solarium\Exception\InvalidArgumentException;
use Solarium\Exception\RuntimeException;
use Solarium\Exception\HttpException;
/**
* cURL HTTP adapter
*
* @author Intervals <info@myintervals.com>
* @package Solarium
* @subpackage Client
*/
class Solarium_Client_Adapter_Curl extends Solarium_Client_Adapter
class Curl extends Configurable implements AdapterInterface
{
/**
* Initialization hook
*
* Checks the availability of Curl_http
*
* @throws RuntimeException
*/
protected function _init()
protected function init()
{
// @codeCoverageIgnoreStart
if (!function_exists('curl_init')) {
throw new Solarium_Exception('cURL is not available, install it to use the CurlHttp adapter');
throw new RuntimeException('cURL is not available, install it to use the CurlHttp adapter');
}
parent::_init();
parent::init();
// @codeCoverageIgnoreEnd
}
/**
* Execute a Solr request using the cURL Http
*
* @param Solarium_Client_Request $request
* @return Solarium_Client_Response
* @param Request $request
* @param Endpoint $endpoint
* @return Response
*/
public function execute($request)
public function execute($request, $endpoint)
{
return $this->_getData($request);
return $this->getData($request, $endpoint);
}
/**
* Execute request
*
* @param Solarium_Client_Request $request
* @return array
* @param Request $request
* @param Endpoint $endpoint
* @return Response
*/
protected function _getData($request)
protected function getData($request, $endpoint)
{
// @codeCoverageIgnoreStart
$handle = $this->createHandle($request);
$handle = $this->createHandle($request, $endpoint);
$httpResponse = curl_exec($handle);
return $this->getResponse($handle, $httpResponse);
......@@ -94,7 +105,7 @@ class Solarium_Client_Adapter_Curl extends Solarium_Client_Adapter
*
* @param resource $handle
* @param string $httpResponse
* @return Solarium_Client_Response
* @return Response
*/
public function getResponse($handle, $httpResponse)
{
......@@ -111,22 +122,25 @@ class Solarium_Client_Adapter_Curl extends Solarium_Client_Adapter
curl_close($handle);
$this->check($data, $headers);
return new Solarium_Client_Response($data, $headers);
return new Response($data, $headers);
// @codeCoverageIgnoreEnd
}
/**
* Create curl handle for a request
*
* @param Solarium_Client_Request $request
* @throws InvalidArgumentException
* @param Request $request
* @param Endpoint $endpoint
* @return resource
*/
public function createHandle($request)
public function createHandle($request, $endpoint)
{
// @codeCoverageIgnoreStart
$uri = $this->getBaseUri() . $request->getUri();
$uri = $endpoint->getBaseUri() . $request->getUri();
$method = $request->getMethod();
$options = $this->_createOptions($request);
$options = $this->createOptions($request, $endpoint);
$handler = curl_init();
curl_setopt($handler, CURLOPT_URL, $uri);
......@@ -134,10 +148,20 @@ class Solarium_Client_Adapter_Curl extends Solarium_Client_Adapter
curl_setopt($handler, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($handler, CURLOPT_TIMEOUT, $options['timeout']);
if ( $proxy = $this->getOption('proxy') ) {
curl_setopt($handler, CURLOPT_PROXY, $proxy);
}
if (!isset($options['headers']['Content-Type'])) {
$options['headers']['Content-Type'] = 'text/xml; charset=utf-8';
}
$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);
}
if (count($options['headers'])) {
$headers = array();
foreach ($options['headers'] as $key => $value) {
......@@ -146,15 +170,19 @@ class Solarium_Client_Adapter_Curl extends Solarium_Client_Adapter
curl_setopt($handler, CURLOPT_HTTPHEADER, $headers);
}
if ($method == Solarium_Client_Request::METHOD_POST) {
if ($method == Request::METHOD_POST) {
curl_setopt($handler, CURLOPT_POST, true);
if ($request->getFileUpload()) {
curl_setopt($handler, CURLOPT_POSTFIELDS, array('content' => '@'.$request->getFileUpload()));
} else {
curl_setopt($handler, CURLOPT_POSTFIELDS, $request->getRawData());
} else if ($method == Solarium_Client_Request::METHOD_GET) {
}
} elseif ($method == Request::METHOD_GET) {
curl_setopt($handler, CURLOPT_HTTPGET, true);
} else if ($method == Solarium_Client_Request::METHOD_HEAD) {
} elseif ($method == Request::METHOD_HEAD) {
curl_setopt($handler, CURLOPT_CUSTOMREQUEST, 'HEAD');
} else {
throw new Solarium_Exception("unsupported method: $method");
throw new InvalidArgumentException("unsupported method: $method");
}
return $handler;
......@@ -164,14 +192,15 @@ class Solarium_Client_Adapter_Curl extends Solarium_Client_Adapter
/**
* Create http request options from request.
*
* @param Solarium_Client_Request $request
* @param Request $request
* @param Endpoint $endpoint
* @return array
*/
protected function _createOptions($request)
protected function createOptions($request, $endpoint)
{
// @codeCoverageIgnoreStart
$options = array(
'timeout' => $this->getTimeout()
'timeout' => $endpoint->getTimeout()
);
foreach ($request->getHeaders() as $headerLine) {
list($header, $value) = explode(':', $headerLine);
......@@ -179,6 +208,7 @@ class Solarium_Client_Adapter_Curl extends Solarium_Client_Adapter
$options['headers'][$header] = trim($value);
}
}
return $options;
// @codeCoverageIgnoreEnd
}
......@@ -186,7 +216,7 @@ class Solarium_Client_Adapter_Curl extends Solarium_Client_Adapter
/**
* Check result of a request
*
* @throws Solarium_Client_HttpException
* @throws HttpException
* @param string $data
* @param array $headers
* @return void
......@@ -196,7 +226,7 @@ class Solarium_Client_Adapter_Curl extends Solarium_Client_Adapter
// 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 Solarium_Client_HttpException("HTTP request failed");
throw new HttpException("HTTP request failed");
}
}
}
......@@ -31,43 +31,48 @@
* @copyright Copyright 2011 Bas de Nooijer <solarium@raspberry.nl>
* @license http://github.com/basdenooijer/solarium/raw/master/COPYING
* @link http://www.solarium-project.org/
*
* @package Solarium
* @subpackage Client
*/
/**
* @namespace
*/
namespace Solarium\Core\Client\Adapter;
use Solarium\Core\Configurable;
use Solarium\Core\Client\Request;
use Solarium\Core\Client\Response;
use Solarium\Core\Client\Endpoint;
use Solarium\Exception\HttpException;
/**
* Basic HTTP adapter using a stream
*
* @package Solarium
* @subpackage Client
*/
class Solarium_Client_Adapter_Http extends Solarium_Client_Adapter
class Http extends Configurable implements AdapterInterface
{
/**
* Handle Solr communication
*
* @throws Solarium_Exception
* @param Solarium_Client_Request $request
* @return Solarium_Client_Response
* @throws HttpException
* @param Request $request
* @param Endpoint $endpoint
* @return Response
*/
public function execute($request)
public function execute($request, $endpoint)
{
$context = $this->createContext($request);
$uri = $this->getBaseUri() . $request->getUri();
$context = $this->createContext($request, $endpoint);
$uri = $endpoint->getBaseUri() . $request->getUri();
list($data, $headers) = $this->_getData($uri, $context);
list($data, $headers) = $this->getData($uri, $context);
$this->check($data, $headers);
return new Solarium_Client_Response($data, $headers);
return new Response($data, $headers);
}
/**
* Check result of a request
*
* @throws Solarium_Client_HttpException
* @throws HttpException
* @param string $data
* @param array $headers
* @return void
......@@ -77,27 +82,37 @@ class Solarium_Client_Adapter_Http extends Solarium_Client_Adapter
// if there is no data and there are no headers it's a total failure,
// a connection to the host was impossible.
if (false === $data && count($headers) == 0) {
throw new Solarium_Client_HttpException("HTTP request failed");
throw new HttpException("HTTP request failed");
}
}
/**
* Create a stream context for a request
*
* @param Solarium_Client_Request $request
* @param Request $request
* @param Endpoint $endpoint
* @return resource
*/
public function createContext($request)
public function createContext($request, $endpoint)
{
$method = $request->getMethod();
$context = stream_context_create(
array('http' => array(
'method' => $method,
'timeout' => $this->getTimeout()
'timeout' => $endpoint->getTimeout()
))
);
if ($method == Solarium_Client_Request::METHOD_POST) {
if ($method == Request::METHOD_POST) {
if ($request->getFileUpload()) {
stream_context_set_option(
$context,
'http',
'content',
file_get_contents($request->getFileUpload())
);
$request->addHeader('Content-Type: multipart/form-data');
} else {
$data = $request->getRawData();
if (null !== $data) {
stream_context_set_option(
......@@ -110,6 +125,12 @@ class Solarium_Client_Adapter_Http extends Solarium_Client_Adapter
$request->addHeader('Content-Type: text/xml; charset=UTF-8');
}
}
}
$authData = $request->getAuthentication();
if ( !empty($authData['username']) && !empty($authData['password'])) {
$request->addHeader('Authorization: Basic ' . base64_encode($authData['username']. ':' . $authData['password'] ));
}
$headers = $request->getHeaders();
if (count($headers) > 0) {
......@@ -131,7 +152,7 @@ class Solarium_Client_Adapter_Http extends Solarium_Client_Adapter
* @param resource $context
* @return array
*/
protected function _getData($uri, $context)
protected function getData($uri, $context)
{
// @codeCoverageIgnoreStart
$data = @file_get_contents($uri, false, $context);
......
......@@ -32,56 +32,67 @@
* @copyright Copyright 2011 Gasol Wu <gasol.wu@gmail.com>
* @license http://github.com/basdenooijer/solarium/raw/master/COPYING
* @link http://www.solarium-project.org/
*
* @package Solarium
* @subpackage Client
*/
/**
* @namespace
*/
namespace Solarium\Core\Client\Adapter;
use Solarium\Core\Configurable;
use Solarium\Core\Client\Request;
use Solarium\Core\Client\Response;
use Solarium\Core\Client\Endpoint;
use Solarium\Exception\RuntimeException;
use Solarium\Exception\HttpException;
use Solarium\Exception\InvalidArgumentException;
/**
* Pecl HTTP adapter
*
* @author Gasol Wu <gasol.wu@gmail.com>
* @package Solarium
* @subpackage Client
*/
class Solarium_Client_Adapter_PeclHttp extends Solarium_Client_Adapter
class PeclHttp extends Configurable implements AdapterInterface
{
/**
* Initialization hook
*
* Checks the availability of pecl_http
*
* @throws RuntimeException
*/
protected function _init()
protected function init()
{
// @codeCoverageIgnoreStart
if (!class_exists('HttpRequest', false)) {
throw new Solarium_Exception('Pecl_http is not available, install it to use the PeclHttp adapter');
throw new RuntimeException('Pecl_http is not available, install it to use the PeclHttp adapter');
}
parent::_init();
parent::init();
// @codeCoverageIgnoreEnd
}
/**
* Execute a Solr request using the Pecl Http
*
* @param Solarium_Client_Request $request
* @return Solarium_Client_Response
* @throws HttpException
* @param Request $request
* @param Endpoint $endpoint
* @return Response
*/
public function execute($request)
public function execute($request, $endpoint)
{
$httpRequest = $this->toHttpRequest($request);
$httpRequest = $this->toHttpRequest($request, $endpoint);
try {
$httpMessage = $httpRequest->send();
} catch (Exception $e) {
throw new Solarium_Client_HttpException($e->getMessage());
} catch (\Exception $e) {
throw new HttpException($e->getMessage());
}
return new Solarium_Client_Response(
return new Response(
$httpMessage->getBody(),
$this->_toRawHeaders($httpMessage)
$this->toRawHeaders($httpMessage)
);
}
......@@ -98,10 +109,10 @@ class Solarium_Client_Adapter_PeclHttp extends Solarium_Client_Adapter
* $headers[0] = 'Content-Type: text/plain';
* </code>
*
* @param $message HttpMessage
* @param $message \HttpMessage
* @return array
*/
protected function _toRawHeaders($message)
protected function toRawHeaders($message)
{
$headers[] = 'HTTP/' . $message->getHttpVersion()
. ' ' . $message->getResponseCode()
......@@ -116,18 +127,20 @@ class Solarium_Client_Adapter_PeclHttp extends Solarium_Client_Adapter
/**
*
* adapt Solarium_Client_Request to HttpRequest
* adapt Request to HttpRequest
*
* {@link http://us.php.net/manual/en/http.constants.php
* HTTP Predefined Constant}
*
* @param Solarium_Client_Request $request
* @throws InvalidArgumentException
* @param Request $request
* @param Endpoint $endpoint
* @param HttpRequest
*/
public function toHttpRequest($request)
public function toHttpRequest($request, $endpoint)
{
$url = $this->getBaseUri() . $request->getUri();
$httpRequest = new HttpRequest($url);
$url = $endpoint->getBaseUri() . $request->getUri();
$httpRequest = new \HttpRequest($url);
$headers = array();
foreach ($request->getHeaders() as $headerLine) {
......@@ -137,28 +150,41 @@ class Solarium_Client_Adapter_PeclHttp extends Solarium_Client_Adapter
}
}
switch($request->getMethod()) {
case Solarium_Client_Request::METHOD_GET:
$authData = $request->getAuthentication();
if ( !empty($authData['username']) && !empty($authData['password'])) {
$headers['Authorization'] = 'Basic ' . base64_encode($authData['username']. ':' . $authData['password'] );
}
switch ($request->getMethod()) {
case Request::METHOD_GET:
$method = HTTP_METH_GET;
break;
case Solarium_Client_Request::METHOD_POST:
case Request::METHOD_POST:
$method = HTTP_METH_POST;
if ($request->getFileUpload()) {
$httpRequest->addPostFile(
'content',
$request->getFileUpload(),
'application/octet-stream; charset=binary'
);
} else {
$httpRequest->setBody($request->getRawData());
if (!isset($headers['Content-Type'])) {
$headers['Content-Type'] = 'text/xml; charset=utf-8';
}
}
break;
case Solarium_Client_Request::METHOD_HEAD:
case Request::METHOD_HEAD:
$method = HTTP_METH_HEAD;
break;
default:
throw new Solarium_Exception(
throw new InvalidArgumentException(
'Unsupported method: ' . $request->getMethod()
);
}
$httpRequest->setMethod($method);
$httpRequest->setOptions(array('timeout' => $this->getTimeout()));
$httpRequest->setOptions(array('timeout' => $endpoint->getTimeout()));
$httpRequest->setHeaders($headers);
return $httpRequest;
......
<?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:
......@@ -29,13 +30,24 @@
* 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
*/
/**
* @namespace
*/
namespace Solarium\Core\Client\Adapter;
use Solarium\Core\Configurable;
use Solarium\Core\Client;
use Solarium\Core\Client\Request;
use Solarium\Core\Client\Response;
use Solarium\Core\Client\Endpoint;
use Solarium\Exception\HttpException;
use Solarium\Exception\OutOfBoundsException;
/**
* Adapter that uses a Zend_Http_Client
*
......@@ -44,19 +56,21 @@
* {@link http://framework.zend.com/manual/en/zend.http.html}
*
* To use this adapter you need to have the Zend Framework available (autoloading)
*
* @package Solarium
* @subpackage Client
*/
class Solarium_Client_Adapter_ZendHttp extends Solarium_Client_Adapter
class ZendHttp extends Configurable implements AdapterInterface
{
/**
* Zend Http instance for communication with Solr
*
* @var Zend_Http_Client
* @var \Zend_Http_Client
*/
protected $zendHttp;
/**
* @var int
*/
protected $_zendHttp;
protected $timeout;
/**
* Set options
......@@ -72,24 +86,24 @@ class Solarium_Client_Adapter_ZendHttp extends Solarium_Client_Adapter
*
* @param array|object $options
* @param boolean $overwrite
* @return Solarium_Client_Adapter_ZendHttp Provides fluent interface
* @return self Provides fluent interface
*/
public function setOptions($options, $overwrite = false)
{
parent::setOptions($options, $overwrite);
// forward options to zendHttp instance
if (null !== $this->_zendHttp) {
if (null !== $this->zendHttp) {
// forward timeout setting
$adapterOptions = array('timeout' => $this->getTimeout());
$adapterOptions = array();
// forward adapter options if available
if (isset($this->_options['options'])) {
$adapterOptions = array_merge($adapterOptions, $this->_options['options']);
if (isset($this->options['options'])) {
$adapterOptions = array_merge($adapterOptions, $this->options['options']);
}
$this->_zendHttp->setConfig($adapterOptions);
$this->zendHttp->setConfig($adapterOptions);
}
return $this;
......@@ -102,12 +116,13 @@ class Solarium_Client_Adapter_ZendHttp extends Solarium_Client_Adapter
* upon first use, using default and/or custom options (the most common use
* case)
*
* @param Zend_Http_Client $zendHttp
* @return Solarium_Client_Adapter_ZendHttp Provides fluent interface
* @param \Zend_Http_Client $zendHttp
* @return self Provides fluent interface
*/
public function setZendHttp($zendHttp)
{
$this->_zendHttp = $zendHttp;
$this->zendHttp = $zendHttp;
return $this;
}
......@@ -121,53 +136,94 @@ class Solarium_Client_Adapter_ZendHttp extends Solarium_Client_Adapter
* options, get the last response and use many other features offered by the
* Zend_Http_Client API.
*
* @return Zend_Http_Client
* @return \Zend_Http_Client
*/
public function getZendHttp()
{
if (null == $this->_zendHttp) {
$options = array('timeout' => $this->getOption('timeout'));
if (null == $this->zendHttp) {
$options = array();
// forward zendhttp options
if (isset($this->_options['options'])) {
if (isset($this->options['options'])) {
$options = array_merge(
$options,
$this->_options['options']
$this->options['options']
);
}
$this->_zendHttp = new Zend_Http_Client(null, $options);
$this->zendHttp = new \Zend_Http_Client(null, $options);
}
return $this->_zendHttp;
return $this->zendHttp;
}
/**
* Execute a Solr request using the Zend_Http_Client instance
*
* @param Solarium_Client_Request $request
* @return Solarium_Client_Response
* @throws HttpException
* @param Request $request
* @param Endpoint $endpoint
* @return Response
*/
public function execute($request)
public function execute($request, $endpoint)
{
$client = $this->getZendHttp();
$client->resetParameters();
switch ($request->getMethod()) {
case Request::METHOD_GET:
$client->setMethod(\Zend_Http_Client::GET);
$client->setParameterGet($request->getParams());
break;
case Request::METHOD_POST:
$client->setMethod(\Zend_Http_Client::POST);
if ($request->getFileUpload()) {
$this->prepareFileUpload($client, $request);
} else {
$client->setParameterGet($request->getParams());
$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->getParams());
break;
default:
throw new OutOfBoundsException('Unsupported method: ' . $request->getMethod());
break;
}
$client->setMethod($request->getMethod());
$client->setUri($this->getBaseUri() . $request->getUri());
$client->setUri($endpoint->getBaseUri() . $request->getUri());
$client->setHeaders($request->getHeaders());
$client->setRawData($request->getRawData());
$this->timeout = $endpoint->getTimeout();
$response = $client->request();
// throw an exception in case of a HTTP error
return $this->prepareResponse(
$request,
$response
);
}
/**
* 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 Solarium_Client_HttpException(
throw new HttpException(
$response->getMessage(),
$response->getStatus()
);
}
if ($request->getMethod() == Solarium_Client_Request::METHOD_HEAD) {
if ($request->getMethod() == Request::METHOD_HEAD) {
$data = '';
} else {
$data = $response->getBody();
......@@ -176,7 +232,24 @@ class Solarium_Client_Adapter_ZendHttp extends Solarium_Client_Adapter
// this is used because getHeaders doesn't return the HTTP header...
$headers = explode("\n", $response->getHeadersAsString());
return new Solarium_Client_Response($data, $headers);
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();
$client->setFileUpload(
'content',
'content',
file_get_contents($filename),
'application/octet-stream; charset=binary'
);
}
}
This diff is collapsed.
......@@ -31,32 +31,20 @@
* @copyright Copyright 2011 Bas de Nooijer <solarium@raspberry.nl>
* @license http://github.com/basdenooijer/solarium/raw/master/COPYING
* @link http://www.solarium-project.org/
*
* @package Solarium
* @subpackage Client
*/
/**
* Base class for all adapters
*
* The goal of an adapter is to accept a query, execute it and return the right
* result object. This is actually quite a complex task as it involves the
* handling of all Solr communication.
*
* The adapter structure allows for varying implementations of this task.
*
* Most adapters will use some sort of HTTP client. In that case the
* Solarium_Client_Request request builders and Solarium_Client_Response
* response parsers can be used to simplify HTTP communication.
* See {@link Solarium_Client_Adapter_Http} as an example.
*
* However an adapter may also implement all logic by itself if needed.
*
* @package Solarium
* @subpackage Client
* @namespace
*/
abstract class Solarium_Client_Adapter extends Solarium_Configurable
namespace Solarium\Core\Client;
use Solarium\Core\Configurable;
/**
* Class for describing an endpoint
*/
class Endpoint extends Configurable
{
/**
* Default options
*
......@@ -65,7 +53,7 @@ abstract class Solarium_Client_Adapter extends Solarium_Configurable
*
* @var array
*/
protected $_options = array(
protected $options = array(
'host' => '127.0.0.1',
'port' => 8983,
'path' => '/solr',
......@@ -79,9 +67,9 @@ abstract class Solarium_Client_Adapter extends Solarium_Configurable
* In this case the path needs to be cleaned of trailing slashes.
* @see setPath()
*/
protected function _init()
protected function init()
{
foreach ($this->_options AS $name => $value) {
foreach ($this->options as $name => $value) {
switch ($name) {
case 'path':
$this->setPath($value);
......@@ -90,15 +78,36 @@ abstract class Solarium_Client_Adapter extends Solarium_Configurable
}
}
/**
* Get key value
*
* @return string
*/
public function getKey()
{
return $this->getOption('key');
}
/**
* Set key value
*
* @param string $value
* @return self Provides fluent interface
*/
public function setKey($value)
{
return $this->setOption('key', $value);
}
/**
* Set host option
*
* @param string $host This can be a hostname or an IP address
* @return Solarium_Client Provides fluent interface
* @return self Provides fluent interface
*/
public function setHost($host)
{
return $this->_setOption('host', $host);
return $this->setOption('host', $host);
}
/**
......@@ -115,11 +124,11 @@ abstract class Solarium_Client_Adapter extends Solarium_Configurable
* Set port option
*
* @param int $port Common values are 80, 8080 and 8983
* @return Solarium_Client Provides fluent interface
* @return self Provides fluent interface
*/
public function setPort($port)
{
return $this->_setOption('port', $port);
return $this->setOption('port', $port);
}
/**
......@@ -138,13 +147,15 @@ abstract class Solarium_Client_Adapter extends Solarium_Configurable
* If the path has a trailing slash it will be removed.
*
* @param string $path
* @return Solarium_Client Provides fluent interface
* @return self Provides fluent interface
*/
public function setPath($path)
{
if (substr($path, -1) == '/') $path = substr($path, 0, -1);
if (substr($path, -1) == '/') {
$path = substr($path, 0, -1);
}
return $this->_setOption('path', $path);
return $this->setOption('path', $path);
}
/**
......@@ -161,11 +172,11 @@ abstract class Solarium_Client_Adapter extends Solarium_Configurable
* Set core option
*
* @param string $core
* @return Solarium_Client Provides fluent interface
* @return self Provides fluent interface
*/
public function setCore($core)
{
return $this->_setOption('core', $core);
return $this->setOption('core', $core);
}
/**
......@@ -182,11 +193,11 @@ abstract class Solarium_Client_Adapter extends Solarium_Configurable
* Set timeout option
*
* @param int $timeout
* @return Solarium_Client Provides fluent interface
* @return self Provides fluent interface
*/
public function setTimeout($timeout)
{
return $this->_setOption('timeout', $timeout);
return $this->setOption('timeout', $timeout);
}
/**
......@@ -199,17 +210,6 @@ abstract class Solarium_Client_Adapter extends Solarium_Configurable
return $this->getOption('timeout');
}
/**
* Execute a request
*
* Abstract method to require an implementation inside all adapters.
*
* @abstract
* @param Solarium_Client_Request $request
* @return Solarium_Client_Response
*/
abstract public function execute($request);
/**
* Get the base url for all requests
*
......
......@@ -31,18 +31,18 @@
* @copyright Copyright 2011 Bas de Nooijer <solarium@raspberry.nl>
* @license http://github.com/basdenooijer/solarium/raw/master/COPYING
* @link http://www.solarium-project.org/
*
* @package Solarium
* @subpackage Client
*/
/**
* @namespace
*/
namespace Solarium\Core\Client;
use Solarium\Exception\HttpException;
/**
* Class for describing a response
*
* @package Solarium
* @subpackage Client
*/
class Solarium_Client_Response
class Response
{
/**
......@@ -50,28 +50,28 @@ class Solarium_Client_Response
*
* @var array
*/
protected $_headers;
protected $headers;
/**
* Body
*
* @var string
*/
protected $_body;
protected $body;
/**
* HTTP response code
*
* @var int
*/
protected $_statusCode;
protected $statusCode;
/**
* HTTP response message
*
* @var string
*/
protected $_statusMessage;
protected $statusMessage;
/**
* Constructor
......@@ -81,10 +81,10 @@ class Solarium_Client_Response
*/
public function __construct($body, $headers = array())
{
$this->_body = $body;
$this->_headers = $headers;
$this->body = $body;
$this->headers = $headers;
$this->_setHeaders($headers);
$this->setHeaders($headers);
}
/**
......@@ -94,7 +94,7 @@ class Solarium_Client_Response
*/
public function getBody()
{
return $this->_body;
return $this->body;
}
/**
......@@ -104,7 +104,7 @@ class Solarium_Client_Response
*/
public function getHeaders()
{
return $this->_headers;
return $this->headers;
}
/**
......@@ -114,7 +114,7 @@ class Solarium_Client_Response
*/
public function getStatusCode()
{
return $this->_statusCode;
return $this->statusCode;
}
/**
......@@ -124,22 +124,23 @@ class Solarium_Client_Response
*/
public function getStatusMessage()
{
return $this->_statusMessage;
return $this->statusMessage;
}
/**
* Set headers
*
* @throws HttpException
* @param array $headers
* @return void
*/
public function _setHeaders($headers)
public function setHeaders($headers)
{
$this->_headers = $headers;
$this->headers = $headers;
// get the status header
$statusHeader = null;
foreach ($headers AS $header) {
foreach ($headers as $header) {
if (substr($header, 0, 4) == 'HTTP') {
$statusHeader = $header;
break;
......@@ -147,14 +148,14 @@ class Solarium_Client_Response
}
if (null == $statusHeader) {
throw new Solarium_Client_HttpException("No HTTP status found");
throw new HttpException("No HTTP status found");
}
// parse header like "$statusInfo[1]" into code and message
// $statusInfo[1] = the HTTP response code
// $statusInfo[2] = the response message
$statusInfo = explode(' ', $statusHeader, 3);
$this->_statusCode = $statusInfo[1];
$this->_statusMessage = $statusInfo[2];
$this->statusCode = $statusInfo[1];
$this->statusMessage = $statusInfo[2];
}
}
......@@ -31,20 +31,22 @@
* @copyright Copyright 2011 Bas de Nooijer <solarium@raspberry.nl>
* @license http://github.com/basdenooijer/solarium/raw/master/COPYING
* @link http://www.solarium-project.org/
*
* @package Solarium
*/
/**
* @namespace
*/
namespace Solarium\Core;
use Solarium\Exception\InvalidArgumentException;
/**
* Base class for configurable classes
*
* All classes extending this class are configurable using the constructor or
* setOption calls. This is the base for many Solarium classes, providing a
* uniform interface for various models.
*
* @package Solarium
*/
class Solarium_Configurable
class Configurable implements ConfigurableInterface
{
/**
......@@ -52,19 +54,19 @@ class Solarium_Configurable
*
* @var array
*/
protected $_options = array(
protected $options = array(
);
/**
* Constructor
*
* If options are passed they will be merged with {@link $_options} using
* If options are passed they will be merged with {@link $options} using
* the {@link setOptions()} method.
*
* After handling the options the {@link _init()} method is called.
*
* @throws Solarium_Exception
* @param array|Zend_Config $options
* @throws InvalidArgumentException
* @param array|\Zend_Config $options
* @return void
*/
public function __construct($options = null)
......@@ -72,19 +74,19 @@ class Solarium_Configurable
if (null !== $options) {
$this->setOptions($options);
} else {
$this->_init();
$this->init();
}
}
/**
* Set options
*
* If $options is an object it will be converted into an array by called
* it's toArray method. This is compatible with the Zend_Config classes in
* If $options is an object, it will be converted into an array by calling
* its toArray method. This is compatible with the Zend_Config classes in
* Zend Framework, but can also easily be implemented in any other object.
*
* @throws Solarium_Exception
* @param array|Zend_Config $options
* @throws InvalidArgumentException
* @param array|\Zend_Config $options
* @param boolean $overwrite True for overwriting existing options, false
* for merging (new values overwrite old ones if needed)
*
......@@ -98,18 +100,20 @@ class Solarium_Configurable
if (is_object($options)) {
$options = $options->toArray();
} else {
throw new Solarium_Exception('Options must be an array or a Zend_Config object');
throw new InvalidArgumentException(
'Options value given to the setOptions() method must be an array or a Zend_Config object'
);
}
}
if (true == $overwrite) {
$this->_options = $options;
$this->options = $options;
} else {
$this->_options = array_merge($this->_options, $options);
$this->options = array_merge($this->options, $options);
}
// re-init for new options
$this->_init();
$this->init();
}
}
......@@ -121,7 +125,7 @@ class Solarium_Configurable
* when the option is passed as a constructor argument.
*
* This hook is called by the constructor after saving the constructor
* arguments in {@link $_options}
* arguments in {@link $options}
*
* @internal This empty implementation can optionally be implemented in
* descending classes. It's not an abstract method on purpose, there are
......@@ -129,7 +133,7 @@ class Solarium_Configurable
*
* @return void
*/
protected function _init()
protected function init()
{
}
......@@ -139,11 +143,11 @@ class Solarium_Configurable
*
* @param string $name
* @param mixed $value
* @return Solarium_Configurable
* @return self Provides fluent interface
*/
protected function _setOption($name, $value)
protected function setOption($name, $value)
{
$this->_options[$name] = $value;
$this->options[$name] = $value;
return $this;
}
......@@ -158,8 +162,8 @@ class Solarium_Configurable
*/
public function getOption($name)
{
if (isset($this->_options[$name])) {
return $this->_options[$name];
if (isset($this->options[$name])) {
return $this->options[$name];
} else {
return null;
}
......@@ -172,7 +176,7 @@ class Solarium_Configurable
*/
public function getOptions()
{
return $this->_options;
return $this->options;
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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