Skip to content
This repository has been archived by the owner on Jan 10, 2018. It is now read-only.

Commit

Permalink
Add HTTP transport
Browse files Browse the repository at this point in the history
  • Loading branch information
vierbergenlars committed Jul 26, 2013
1 parent 4e81184 commit 96f04a0
Show file tree
Hide file tree
Showing 5 changed files with 283 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -0,0 +1 @@
vendor
22 changes: 22 additions & 0 deletions composer.json
@@ -0,0 +1,22 @@
{
"name": "vierbergenlars/norch-php-client",
"description": "PHP client for the norch search server",
"require": {
"ext-curl": "*"
},
"require-dev": {
"vierbergenlars/simpletest": "1.1.2"
},
"license": "MIT",
"authors": [
{
"name": "Lars Vierbergen",
"email": "vierbergenlars@gmail.com"
}
],
"autoload": {
"psr-0": {
"vierbergenlars\\Norch": "lib/"
}
}
}
189 changes: 189 additions & 0 deletions lib/vierbergenlars/Norch/Transport/Http.php
@@ -0,0 +1,189 @@
<?php

namespace vierbergenlars\Norch\Transport;

/**
* HTTP as transport layer for Norch queries
*
* {@inheritDoc}
*/
class Http implements TransportInterface
{
/**
* The path to the place where Norch is listening
* @var string
*/
private $base_path;

/**
* Creates a new HTTP transport layer
* @param string $base_path The base path of the Norch server
*/
public function __construct($base_path = 'http://localhost:3000/')
{
$this->base_path = $base_path;
}

private static function addPostBody($ch, $fields = array(), $files = array())
{
$boundary = '--------------'.uniqid();

$data = '';

foreach($fields as $name=>$value) {
$data.='--'.$boundary."\r\n";
$data.='Content-Disposition: form-data; name="'.$name.'"';
$data.="\r\n\r\n";
$data.=$value;
$data.="\r\n";
}

foreach($files as $name=>$file) {
$data.='--'.$boundary."\r\n";
$data.='Content-Disposition: form-data; name="'.$name.'"; filename="'.$file['filename'].'"'."\r\n";
$data.="Content-Type: application/octet-stream\r\n\r\n";
$data.=$file['data'];
$data.="\r\n";
}

$data.='--'.$boundary.'--'."\r\n";

curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: multipart/form-data; boundary='.$boundary,
'Content-Length: '.strlen($data)
));
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
}

/**
* Adds a set of documents to the index
* @param array $documents An array of documents to submit. Each document is an array. The document may not have a key named 'id'.
* @param array $filter Array of fields that can be used for faceted search. Can only contain fields that are arrays in the document.
* @return boolean
* @throws TransportException
*/
public function indexBatch(array $documents, array $filter)
{
$json_docs = json_encode($documents);
$docid = uniqid();
$ch = curl_init($this->base_path.'indexer');
if(!$ch)
throw new TransportException('Cannot open a cURL session');
self::addPostBody($ch, array(
'filterOn'=>implode(',', $filter)
), array(
'document'=> array(
'filename'=>$docid.'.json',
'data'=> $json_docs
)
));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$reply = curl_exec($ch);
curl_close($ch);
if($reply === 'indexed batch: '.$docid.'.json'."\r\n")
return true;
return false;
}

/**
* Perform a search query
*
* @param string $query The search query
* @param array $searchFields An array of fields to search in
* @param array $facets An array of fields to facet on
* @param array $filters Limit search to fields with a particular value(s). Each field contains an array of acceptable values.
* @param int $offset The offset to start in the result set
* @param int $pagesize The size of each page
* @param array $weight The weights to give each field.
* @return array Raw json decoded data from the search server
* @throws TransportException
*/
public function search(
$query,
array $searchFields = null,
array $facets = null,
array $filters = null,
$offset = 0,
$pagesize = 10,
array $weight = null
)
{
$querystring = '?q='.$query;
if($searchFields) {
$querystring.='&searchFields='.implode(',', $searchFields);
}
if($facets) {
$querystring.='&facets='.implode(',', $facets);
}
if($filters) {
foreach($filters as $name=>$values)
foreach($values as $value)
$querystring.='&filter['.$name.'][]='.$value;
}
if($offset) {
$querystring .= '&offset='.$offset;
}
if($pagesize != 10) {
$querystring .= '&pagesize='.$pagesize;
}
if($weight) {
foreach($weight as $name=>$values)
foreach($values as $value)
$querystring.='&weight['.$name.'][]='.$value;
}


$ch = curl_init($this->base_path.'search'.$querystring);
if(!$ch)
throw new TransportException('Cannot open a cURL session');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$resp = curl_exec($ch);
curl_close($ch);

return json_decode($resp, true);
}

/**
* Removes a document with a specific ID
*
* @param int $docId
* @return boolean
* @throws TransportException
*/
public function deleteDoc($docId)
{
$ch = curl_init($this->base_path.'delete');
if(!$ch)
throw new TransportException('Cannot open a cURL session');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, array(
'docID'=>$docId
));
$resp = curl_exec($ch);
curl_close($ch);
if($resp === "deleted ".$docId."\r\n")
return true;
return false;
}

/**
* Retrieve meta-data about the index
*
* @return array The raw JSON decoded data from the search server
* @throws TransportException
*/
public function getIndexMetadata()
{
$ch = curl_init($this->base_path.'indexData');
if(!$ch)
throw new TransportException('Cannot open a cURL session');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$resp = curl_exec($ch);
curl_close($ch);

return json_decode($resp, true);
}

}
8 changes: 8 additions & 0 deletions lib/vierbergenlars/Norch/Transport/TransportException.php
@@ -0,0 +1,8 @@
<?php

namespace vierbergenlars\Norch\Transport;

class TransportException extends \RuntimeException
{

}
63 changes: 63 additions & 0 deletions lib/vierbergenlars/Norch/Transport/TransportInterface.php
@@ -0,0 +1,63 @@
<?php

namespace vierbergenlars\Norch\Transport;

/**
* Interface all transport objects should implement
*
* The Transport layer provides a low-level interface to the Norch search server.
* The transport layer is responsible for serializing of the passed data,
* and unserialisation of the received data. It should not modify requests or responses.
*/
interface TransportInterface
{
/**
* Adds a set of documents to the index
*
* @param array $documents An array of documents to submit. Each document is an array. The document may not have a key named 'id'.
* @param array $filter Array of fields that can be used for faceted search. Can only contain fields that are arrays in the document.
* @return boolean
* @throws TransportException
*/
public function indexBatch(array $documents, array $filter);

/**
* Perform a search query
*
* @param string $query The search query
* @param array $searchFields An array of fields to search in
* @param array $facets An array of fields to facet on
* @param array $filters Limit search to fields with a particular value(s). Each field contains an array of acceptable values.
* @param int $offset The offset to start in the result set
* @param int $pagesize The size of each page
* @param array $weight The weights to give each field.
* @return array Raw json decoded data from the search server
* @throws TransportException
*/
public function search(
$query,
array $searchFields = null,
array $facets = null,
array $filters = null,
$offset = 0,
$pagesize = 10,
array $weight = null
);

/**
* Removes a document with a specific ID
*
* @param int|string $docId
* @return boolean
* @throws TransportException
*/
public function deleteDoc($docId);

/**
* Retrieve meta-data about the index
*
* @return array The raw JSON decoded data from the search server
* @throws TransportException
*/
public function getIndexMetadata();
}

0 comments on commit 96f04a0

Please sign in to comment.