Source for file Service.php

Documentation is available at Service.php

  1. <?php
  2. /**
  3.  * @copyright Copyright 2007 Conduit Internet Technologies, Inc. (http://conduit-it.com)
  4.  * @license Apache Licence, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
  5.  *
  6.  *  Licensed under the Apache License, Version 2.0 (the "License");
  7.  *  you may not use this file except in compliance with the License.
  8.  *  You may obtain a copy of the License at
  9.  *
  10.  *      http://www.apache.org/licenses/LICENSE-2.0
  11.  *
  12.  *  Unless required by applicable law or agreed to in writing, software
  13.  *  distributed under the License is distributed on an "AS IS" BASIS,
  14.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15.  *  See the License for the specific language governing permissions and
  16.  *  limitations under the License.
  17.  *
  18.  * @package Apache
  19.  * @subpackage Solr
  20.  * @author Donovan Jimenez <djimenez@conduit-it.com>
  21.  */
  22.  
  23. require_once('Apache/Solr/Document.php');
  24. require_once('Apache/Solr/Response.php');
  25.  
  26. /**
  27.  * Starting point for the Solr API. Represents a Solr server resource and has
  28.  * methods for pinging, adding, deleting, committing, optimizing and searching.
  29.  *
  30.  * Example Usage:
  31.  * <code>
  32.  * ...
  33.  * $solr = new Apache_Solr_Service(); //or explicitly new Apache_Solr_Service('localhost', 8180, '/solr')
  34.  *
  35.  * if ($solr->ping())
  36.  * {
  37.  *         $solr->deleteByQuery('*:*'); //deletes ALL documents - be careful :)
  38.  *
  39.  *         $document = new Apache_Solr_Document();
  40.  *         $document->id = uniqid(); //or something else suitably unique
  41.  *
  42.  *         $document->title = 'Some Title';
  43.  *         $document->content = 'Some content for this wonderful document. Blah blah blah.';
  44.  *
  45.  *         $solr->addDocument($document);     //if you're going to be adding documents in bulk using addDocuments
  46.  *                                         //with an array of documents is faster
  47.  *
  48.  *         $solr->commit(); //commit to see the deletes and the document
  49.  *         $solr->optimize(); //merges multiple segments into one
  50.  *
  51.  *         //and the one we all care about, search!
  52.  *         //any other common or custom parameters to the request handler can go in the
  53.  *         //optional 4th array argument.
  54.  *         $solr->search('content:blah', 0, 10, array('sort' => 'timestamp desc'));
  55.  * }
  56.  * ...
  57.  * </code>
  58.  *
  59.  * @todo Investigate using other HTTP clients other than file_get_contents built-in handler. Could provide performance
  60.  *  improvements when dealing with multiple requests by using HTTP's keep alive functionality
  61.  */
  62. {
  63.     /**
  64.      * Response version we support
  65.      */
  66.     const SOLR_VERSION '1.2';
  67.  
  68.     /**
  69.      * Response writer we support
  70.      *
  71.      * @todo Solr 1.3 release may change this to SerializedPHP or PHP implementation
  72.      */
  73.     const SOLR_WRITER 'json';
  74.  
  75.     /**
  76.      * NamedList Treatment constants
  77.      */
  78.     const NAMED_LIST_FLAT 'flat';
  79.     const NAMED_LIST_MAP 'map';
  80.  
  81.     /**
  82.      * Servlet mappings
  83.      */
  84.     const PING_SERVLET 'admin/ping';
  85.     const UPDATE_SERVLET 'update';
  86.     const SEARCH_SERVLET 'select';
  87.     const THREADS_SERVLET 'admin/threads';
  88.  
  89.     /**
  90.      * Server identification strings
  91.      *
  92.      * @var string 
  93.      */
  94.     protected $_host$_port$_path;
  95.  
  96.     /**
  97.      * Whether {@link Apache_Solr_Response} objects should create {@link Apache_Solr_Document}s in
  98.      * the returned parsed data
  99.      *
  100.      * @var boolean 
  101.      */
  102.     protected $_createDocuments = true;
  103.  
  104.     /**
  105.      * Whether {@link Apache_Solr_Response} objects should have multivalue fields with only a single value
  106.      * collapsed to appear as a single value would.
  107.      *
  108.      * @var boolean 
  109.      */
  110.     protected $_collapseSingleValueArrays = true;
  111.  
  112.     /**
  113.      * How NamedLists should be formatted in the output.  This specifically effects facet counts. Valid values
  114.      * are {@link Apache_Solr_Service::NAMED_LIST_MAP} (default) or {@link Apache_Solr_Service::NAMED_LIST_FLAT}.
  115.      *
  116.      * @var string 
  117.      */
  118.     protected $_namedListTreatment = self::NAMED_LIST_MAP;
  119.  
  120.     /**
  121.      * Query delimiters. Someone might want to be able to change
  122.      * these (to use &amp; instead of & for example), so I've provided them.
  123.      *
  124.      * @var string 
  125.      */
  126.     protected $_queryDelimiter = '?'$_queryStringDelimiter = '&';
  127.  
  128.     /**
  129.      * Constructed servlet full path URLs
  130.      *
  131.      * @var string 
  132.      */
  133.     protected $_updateUrl$_searchUrl$_threadsUrl;
  134.  
  135.     /**
  136.      * Keep track of whether our URLs have been constructed
  137.      *
  138.      * @var boolean 
  139.      */
  140.     protected $_urlsInited = false;
  141.  
  142.     /**
  143.      * Stream context for posting
  144.      *
  145.      * @var resource 
  146.      */
  147.     protected $_postContext;
  148.  
  149.     /**
  150.      * Escape a value for special query characters such as ':', '(', ')', '*', '?', etc.
  151.      *
  152.      * NOTE: inside a phrase fewer characters need escaped, use {@link Apache_Solr_Service::escapePhrase()} instead
  153.      *
  154.      * @param string $value 
  155.      * @return string 
  156.      */
  157.     static public function escape($value)
  158.     {
  159.         //list taken from http://lucene.apache.org/java/docs/queryparsersyntax.html#Escaping%20Special%20Characters
  160.         $pattern '/(\+|-|&&|\|\||!|\(|\)|\{|}|\[|]|\^|"|~|\*|\?|:|\\\)/';
  161.         $replace '\\\$1';
  162.  
  163.         return preg_replace($pattern$replace$value);
  164.     }
  165.  
  166.     /**
  167.      * Escape a value meant to be contained in a phrase for special query characters
  168.      *
  169.      * @param string $value 
  170.      * @return string 
  171.      */
  172.     static public function escapePhrase($value)
  173.     {
  174.         $pattern '/("|\\\)/';
  175.         $replace '\\\$1';
  176.  
  177.         return preg_replace($pattern$replace$value);
  178.     }
  179.  
  180.     /**
  181.      * Convenience function for creating phrase syntax from a value
  182.      *
  183.      * @param string $value 
  184.      * @return string 
  185.      */
  186.     static public function phrase($value)
  187.     {
  188.         return '"' self::escapePhrase($value'"';
  189.     }
  190.  
  191.     /**
  192.      * Constructor. All parameters are optional and will take on default values
  193.      * if not specified.
  194.      *
  195.      * @param string $host 
  196.      * @param string $port 
  197.      * @param string $path 
  198.      */
  199.     public function __construct($host 'localhost'$port 8180$path '/solr/')
  200.     {
  201.         $this->setHost($host);
  202.         $this->setPort($port);
  203.         $this->setPath($path);
  204.  
  205.         $this->_initUrls();
  206.  
  207.         //set up the stream context for posting with file_get_contents
  208.         $contextOpts array(
  209.             'http' => array(
  210.                 'method' => 'POST',
  211.                 'header' => "Content-Type: text/xml; charset=UTF-8\r\n" //php.net example showed \r\n at the end
  212.             )
  213.         );
  214.  
  215.         $this->_postContext = stream_context_create($contextOpts);
  216.     }
  217.  
  218.     /**
  219.      * Return a valid http URL given this server's host, port and path and a provided servlet name
  220.      *
  221.      * @param string $servlet 
  222.      * @return string 
  223.      */
  224.     protected function _constructUrl($servlet$params array())
  225.     {
  226.         if (count($params))
  227.         {
  228.             //escape all parameters appropriately for inclusion in the query string
  229.             $escapedParams array();
  230.  
  231.             foreach ($params as $key => $value)
  232.             {
  233.                 $escapedParams[urlencode($key'=' urlencode($value);
  234.             }
  235.  
  236.             $queryString $this->_queryDelimiter . implode($this->_queryStringDelimiter$escapedParams);
  237.         }
  238.         else
  239.         {
  240.             $queryString '';
  241.         }
  242.  
  243.         return 'http://' $this->_host . ':' $this->_port . $this->_path . $servlet $queryString;
  244.     }
  245.  
  246.     /**
  247.      * Construct the Full URLs for the three servlets we reference
  248.      */
  249.     protected function _initUrls()
  250.     {
  251.         //Initialize our full servlet URLs now that we have server information
  252.         $this->_updateUrl = $this->_constructUrl(self::UPDATE_SERVLETarray('wt' => self::SOLR_WRITER ));
  253.         $this->_searchUrl = $this->_constructUrl(self::SEARCH_SERVLET);
  254.         $this->_threadsUrl = $this->_constructUrl(self::THREADS_SERVLETarray('wt' => self::SOLR_WRITER ));
  255.  
  256.         $this->_urlsInited = true;
  257.     }
  258.  
  259.     /**
  260.      * Central method for making a get operation against this Solr Server
  261.      *
  262.      * @param string $url 
  263.      * @param float $timeout Read timeout in seconds
  264.      * @return Apache_Solr_Response 
  265.      *
  266.      * @todo implement timeout ability
  267.      * @throws Exception If a non 200 response status is returned
  268.      */
  269.     protected function _sendRawGet($url$timeout FALSE)
  270.     {
  271.         //$http_response_header is set by file_get_contents
  272.         $response new Apache_Solr_Response(@file_get_contents($url)$http_response_header$this->_createDocuments$this->_collapseSingleValueArrays);
  273.  
  274.         if ($response->getHttpStatus(!= 200)
  275.         {
  276.             throw new Exception('"' $response->getHttpStatus('" Status: ' $response->getHttpStatusMessage()$response->getHttpStatus());
  277.         }
  278.  
  279.         return $response;
  280.     }
  281.  
  282.     /**
  283.      * Central method for making a post operation against this Solr Server
  284.      *
  285.      * @param string $url 
  286.      * @param string $rawPost 
  287.      * @param float $timeout Read timeout in seconds
  288.      * @param string $contentType 
  289.      * @return Apache_Solr_Response 
  290.      *
  291.      * @throws Exception If a non 200 response status is returned
  292.      */
  293.     protected function _sendRawPost($url$rawPost$timeout FALSE$contentType 'text/xml; charset=UTF-8')
  294.     {
  295.         //ensure content type is correct
  296.         stream_context_set_option($this->_postContext'http''header''Content-Type: ' $contentType);
  297.  
  298.         //set the read timeout if specified
  299.         if ($timeout !== FALSE)
  300.         {
  301.             stream_context_set_option($this->_postContext'http''timeout'$timeout);
  302.         }
  303.  
  304.         //set the content
  305.         stream_context_set_option($this->_postContext'http''content'$rawPost);
  306.  
  307.         //$http_response_header is set by file_get_contents
  308.         $response new Apache_Solr_Response(@file_get_contents($urlfalse$this->_postContext)$http_response_header$this->_createDocuments$this->_collapseSingleValueArrays);
  309.  
  310.         if ($response->getHttpStatus(!= 200)
  311.         {
  312.             throw new Exception('"' $response->getHttpStatus('" Status: ' $response->getHttpStatusMessage()$response->getHttpStatus());
  313.         }
  314.  
  315.         return $response;
  316.     }
  317.  
  318.     /**
  319.      * Returns the set host
  320.      *
  321.      * @return string 
  322.      */
  323.     public function getHost()
  324.     {
  325.         return $this->_host;
  326.     }
  327.  
  328.     /**
  329.      * Set the host used. If empty will fallback to constants
  330.      *
  331.      * @param string $host 
  332.      */
  333.     public function setHost($host)
  334.     {
  335.         //Use the provided host or use the default
  336.         if (empty($host))
  337.         {
  338.             throw new Exception('Host parameter is empty');
  339.         }
  340.         else
  341.         {
  342.             $this->_host = $host;
  343.         }
  344.  
  345.         if ($this->_urlsInited)
  346.         {
  347.             $this->_initUrls();
  348.         }
  349.     }
  350.  
  351.     /**
  352.      * Get the set port
  353.      *
  354.      * @return integer 
  355.      */
  356.     public function getPort()
  357.     {
  358.         return $this->_port;
  359.     }
  360.  
  361.     /**
  362.      * Set the port used. If empty will fallback to constants
  363.      *
  364.      * @param integer $port 
  365.      */
  366.     public function setPort($port)
  367.     {
  368.         //Use the provided port or use the default
  369.         $port = (int) $port;
  370.  
  371.         if ($port <= 0)
  372.         {
  373.             throw new Exception('Port is not a valid port number');
  374.         }
  375.         else
  376.         {
  377.             $this->_port = $port;
  378.         }
  379.  
  380.         if ($this->_urlsInited)
  381.         {
  382.             $this->_initUrls();
  383.         }
  384.     }
  385.  
  386.     /**
  387.      * Get the set path.
  388.      *
  389.      * @return string 
  390.      */
  391.     public function getPath()
  392.     {
  393.         return $this->_path;
  394.     }
  395.  
  396.     /**
  397.      * Set the path used. If empty will fallback to constants
  398.      *
  399.      * @param string $path 
  400.      */
  401.     public function setPath($path)
  402.     {
  403.         $path trim($path'/');
  404.  
  405.         $this->_path = '/' $path '/';
  406.  
  407.         if ($this->_urlsInited)
  408.         {
  409.             $this->_initUrls();
  410.         }
  411.     }
  412.  
  413.     /**
  414.      * Set the create documents flag. This determines whether {@link Apache_Solr_Response} objects will
  415.      * parse the response and create {@link Apache_Solr_Document} instances in place.
  416.      *
  417.      * @param unknown_type $createDocuments 
  418.      */
  419.     public function setCreateDocuments($createDocuments)
  420.     {
  421.         $this->_createDocuments = (bool) $createDocuments;
  422.     }
  423.  
  424.     /**
  425.      * Get the current state of teh create documents flag.
  426.      *
  427.      * @return boolean 
  428.      */
  429.     public function getCreateDocuments()
  430.     {
  431.         return $this->_createDocuments;
  432.     }
  433.  
  434.     /**
  435.      * Set the collapse single value arrays flag.
  436.      *
  437.      * @param boolean $collapseSingleValueArrays 
  438.      */
  439.     public function setCollapseSingleValueArrays($collapseSingleValueArrays)
  440.     {
  441.         $this->_collapseSingleValueArrays = (bool) $collapseSingleValueArrays;
  442.     }
  443.  
  444.     /**
  445.      * Get the current state of the collapse single value arrays flag.
  446.      *
  447.      * @return boolean 
  448.      */
  449.     public function getCollapseSingleValueArrays()
  450.     {
  451.         return $this->_collapseSingleValueArrays;
  452.     }
  453.  
  454.     /**
  455.      * Set how NamedLists should be formatted in the response data. This mainly effects
  456.      * the facet counts format.
  457.      *
  458.      * @param string $namedListTreatment 
  459.      * @throws Exception If invalid option is set
  460.      */
  461.     public function setNamedListTreatmet($namedListTreatment)
  462.     {
  463.         switch ((string) $namedListTreatment)
  464.         {
  465.             case Apache_Solr_Service::NAMED_LIST_FLAT:
  466.                 $this->_namedListTreatment = Apache_Solr_Service::NAMED_LIST_FLAT;
  467.                 break;
  468.  
  469.             case Apache_Solr_Service::NAMED_LIST_MAP:
  470.                 $this->_namedListTreatment = Apache_Solr_Service::NAMED_LIST_MAP;
  471.                 break;
  472.  
  473.             default:
  474.                 throw new Exception('Not a valid named list treatement option');
  475.         }
  476.     }
  477.  
  478.     /**
  479.      * Get the current setting for named list treatment.
  480.      *
  481.      * @return string 
  482.      */
  483.     public function getNamedListTreatment()
  484.     {
  485.         return $this->_namedListTreatment;
  486.     }
  487.  
  488.  
  489.     /**
  490.      * Set the string used to separate the path form the query string.
  491.      * Defaulted to '?'
  492.      *
  493.      * @param string $queryDelimiter 
  494.      */
  495.     public function setQueryDelimiter($queryDelimiter)
  496.     {
  497.         $this->_queryDelimiter = $queryDelimiter;
  498.     }
  499.  
  500.     /**
  501.      * Set the string used to separate the parameters in thequery string
  502.      * Defaulted to '&'
  503.      *
  504.      * @param string $queryStringDelimiter 
  505.      */
  506.     public function setQueryStringDelimiter($queryStringDelimiter)
  507.     {
  508.         $this->_queryStringDelimiter = $queryStringDelimiter;
  509.     }
  510.  
  511.     /**
  512.      * Call the /admin/ping servlet, can be used to quickly tell if a connection to the
  513.      * server is able to be made.
  514.      *
  515.      * @param float $timeout maximum time to wait for ping in seconds, -1 for unlimited (default is 2)
  516.      * @return float Actual time taken to ping the server, FALSE if timeout occurs
  517.      */
  518.     public function ping($timeout 2)
  519.     {
  520.         $timeout = (float) $timeout;
  521.  
  522.         if ($timeout <= 0)
  523.         {
  524.             $timeout = -1;
  525.         }
  526.  
  527.         $start microtime(true);
  528.  
  529.         //to prevent strict errors
  530.         $errno 0;
  531.         $errstr '';
  532.  
  533.         //try to connect to the host with timeout
  534.         $fp fsockopen($this->_host$this->_port$errno$errstr$timeout);
  535.  
  536.         if ($fp)
  537.         {
  538.             //If we have a timeout set, then determine the amount of time we have left
  539.             //in the request and set the stream timeout for the write operation
  540.             if ($timeout 0)
  541.             {
  542.                 //do the calculation
  543.                 $writeTimeout $timeout (microtime(true$start);
  544.  
  545.                 //check if we're out of time
  546.                 if ($writeTimeout <= 0)
  547.                 {
  548.                     fclose($fp);
  549.                     return false;
  550.                 }
  551.  
  552.                 //convert to microseconds and set the stream timeout
  553.                 $writeTimeoutInMicroseconds = (int) $writeTimeout 1000000;
  554.                 stream_set_timeout($fp0$writeTimeoutInMicroseconds);
  555.             }
  556.  
  557.             $request =     'HEAD ' $this->_path . self::PING_SERVLET ' HTTP/1.1' "\r\n" .
  558.                         'host: ' $this->_host . "\r\n" .
  559.                         'Connection: close' "\r\n" .
  560.                         "\r\n";
  561.  
  562.             fwrite($fp$request);
  563.  
  564.             //check the stream meta data to see if we timed out during the operation
  565.             $metaData stream_get_meta_data($fp);
  566.  
  567.             if (isset($metaData['timeout']&& $metaData['timeout'])
  568.             {
  569.                 fclose($fp);
  570.                 return false;
  571.             }
  572.  
  573.  
  574.             //if we have a timeout set and have made it this far, determine the amount of time
  575.             //still remaining and set the timeout appropriately before the read operation
  576.             if ($timeout 0)
  577.             {
  578.                 //do the calculation
  579.                 $readTimeout $timeout (microtime(true$start);
  580.  
  581.                 //check if we've run out of time
  582.                 if ($readTimeout <= 0)
  583.                 {
  584.                     fclose($fp);
  585.                     return false;
  586.                 }
  587.  
  588.                 //convert to microseconds and set the stream timeout
  589.                 $readTimeoutInMicroseconds $readTimeout 1000000;
  590.                 stream_set_timeout($fp0$readTimeoutInMicroseconds);
  591.             }
  592.  
  593.             //at the very least we should get a response header line of
  594.             //HTTP/1.1 200 OK
  595.             $response fread($fp15);
  596.  
  597.             //check the stream meta data to see if we timed out during the operation
  598.             $metaData stream_get_meta_data($fp);
  599.             fclose($fp)//we're done with the connection - ignore the rest
  600.  
  601.             if (isset($metaData['timeout']&& $metaData['timeout'])
  602.             {
  603.                 return false;
  604.             }
  605.  
  606.             //finally, check the response header line
  607.             if ($response != 'HTTP/1.1 200 OK')
  608.             {
  609.                 return false;
  610.             }
  611.  
  612.             //we made it, return the approximate ping time
  613.             return microtime(true$start;
  614.         }
  615.  
  616.         //we weren't able to make a connection
  617.         return false;
  618.     }
  619.  
  620.     /**
  621.      * Call the /admin/threads servlet and retrieve information about all threads in the
  622.      * Solr servlet's thread group. Useful for diagnostics.
  623.      *
  624.      * @return Apache_Solr_Response 
  625.      *
  626.      * @throws Exception If an error occurs during the service call
  627.      */
  628.     public function threads()
  629.     {
  630.         return $this->_sendRawGet($this->_threadsUrl);
  631.     }
  632.  
  633.     /**
  634.      * Raw Add Method. Takes a raw post body and sends it to the update service.  Post body
  635.      * should be a complete and well formed "add" xml document.
  636.      *
  637.      * @param string $rawPost 
  638.      * @return Apache_Solr_Response 
  639.      *
  640.      * @throws Exception If an error occurs during the service call
  641.      */
  642.     public function add($rawPost)
  643.     {
  644.         return $this->_sendRawPost($this->_updateUrl$rawPost);
  645.     }
  646.  
  647.     /**
  648.      * Add a Solr Document to the index
  649.      *
  650.      * @param Apache_Solr_Document $document 
  651.      * @param boolean $allowDups 
  652.      * @param boolean $overwritePending 
  653.      * @param boolean $overwriteCommitted 
  654.      * @return Apache_Solr_Response 
  655.      *
  656.      * @throws Exception If an error occurs during the service call
  657.      */
  658.     public function addDocument(Apache_Solr_Document $document$allowDups false$overwritePending true$overwriteCommitted true)
  659.     {
  660.         $dupValue $allowDups 'true' 'false';
  661.         $pendingValue $overwritePending 'true' 'false';
  662.         $committedValue $overwriteCommitted 'true' 'false';
  663.  
  664.         $rawPost '<add allowDups="' $dupValue '" overwritePending="' $pendingValue '" overwriteCommitted="' $committedValue '">';
  665.         $rawPost .= $this->_documentToXmlFragment($document);
  666.         $rawPost .= '</add>';
  667.  
  668.         return $this->add($rawPost);
  669.     }
  670.  
  671.     /**
  672.      * Add an array of Solr Documents to the index all at once
  673.      *
  674.      * @param array $documents Should be an array of Apache_Solr_Document instances
  675.      * @param boolean $allowDups 
  676.      * @param boolean $overwritePending 
  677.      * @param boolean $overwriteCommitted 
  678.      * @return Apache_Solr_Response 
  679.      *
  680.      * @throws Exception If an error occurs during the service call
  681.      */
  682.     public function addDocuments($documents$allowDups false$overwritePending true$overwriteCommitted true)
  683.     {
  684.         $dupValue $allowDups 'true' 'false';
  685.         $pendingValue $overwritePending 'true' 'false';
  686.         $committedValue $overwriteCommitted 'true' 'false';
  687.  
  688.         $rawPost '<add allowDups="' $dupValue '" overwritePending="' $pendingValue '" overwriteCommitted="' $committedValue '">';
  689.  
  690.         foreach ($documents as $document)
  691.         {
  692.             if ($document instanceof Apache_Solr_Document)
  693.             {
  694.                 $rawPost .= $this->_documentToXmlFragment($document);
  695.             }
  696.         }
  697.  
  698.         $rawPost .= '</add>';
  699.  
  700.         return $this->add($rawPost);
  701.     }
  702.  
  703.     /**
  704.      * Create an XML fragment from a {@link Apache_Solr_Document} instance appropriate for use inside a Solr add call
  705.      *
  706.      * @return string 
  707.      */
  708.     protected function _documentToXmlFragment(Apache_Solr_Document $document)
  709.     {
  710.         $xml '<doc>';
  711.  
  712.         foreach ($document as $key => $value)
  713.         {
  714.             $key htmlspecialchars($keyENT_QUOTES'UTF-8');
  715.  
  716.             if (is_array($value))
  717.             {
  718.                 foreach ($value as $multivalue)
  719.                 {
  720.                     $multivalue htmlspecialchars($multivalueENT_NOQUOTES'UTF-8');
  721.  
  722.                     $xml .= '<field name="' $key '">' $multivalue '</field>';
  723.                 }
  724.             }
  725.             else
  726.             {
  727.                 $value htmlspecialchars($valueENT_NOQUOTES'UTF-8');
  728.  
  729.                 $xml .= '<field name="' $key '">' $value '</field>';
  730.             }
  731.         }
  732.  
  733.         $xml .= '</doc>';
  734.  
  735.         return $xml;
  736.     }
  737.  
  738.     /**
  739.      * Send a commit command.  Will be synchronous unless both wait parameters are set to false.
  740.      *
  741.      * @param boolean $optimize Defaults to true
  742.      * @param boolean $waitFlush Defaults to true
  743.      * @param boolean $waitSearcher Defaults to true
  744.      * @param float $timeout Maximum expected duration (in seconds) of the commit operation on the server (otherwise, will throw a communication exception). Defaults to 1 hour
  745.      * @return Apache_Solr_Response 
  746.      *
  747.      * @throws Exception If an error occurs during the service call
  748.      */
  749.     public function commit($optimize true$waitFlush true$waitSearcher true$timeout 3600)
  750.     {
  751.         $optimizeValue $optimize 'true' 'false';
  752.         $flushValue $waitFlush 'true' 'false';
  753.         $searcherValue $waitSearcher 'true' 'false';
  754.  
  755.         $rawPost '<commit optimize="' $optimizeValue '" waitFlush="' $flushValue '" waitSearcher="' $searcherValue '" />';
  756.  
  757.         return $this->_sendRawPost($this->_updateUrl$rawPost$timeout);
  758.     }
  759.  
  760.     /**
  761.      * Raw Delete Method. Takes a raw post body and sends it to the update service. Body should be
  762.      * a complete and well formed "delete" xml document
  763.      *
  764.      * @param string $rawPost Expected to be utf-8 encoded xml document
  765.      * @return Apache_Solr_Response 
  766.      *
  767.      * @throws Exception If an error occurs during the service call
  768.      */
  769.     public function delete($rawPost)
  770.     {
  771.         return $this->_sendRawPost($this->_updateUrl$rawPost);
  772.     }
  773.  
  774.     /**
  775.      * Create a delete document based on document ID
  776.      *
  777.      * @param string $id Expected to be utf-8 encoded
  778.      * @param boolean $fromPending 
  779.      * @param boolean $fromCommitted 
  780.      * @return Apache_Solr_Response 
  781.      *
  782.      * @throws Exception If an error occurs during the service call
  783.      */
  784.     public function deleteById($id$fromPending true$fromCommitted true)
  785.     {
  786.         $pendingValue $fromPending 'true' 'false';
  787.         $committedValue $fromCommitted 'true' 'false';
  788.  
  789.         //escape special xml characters
  790.         $id htmlspecialchars($idENT_NOQUOTES'UTF-8');
  791.  
  792.         $rawPost '<delete fromPending="' $pendingValue '" fromCommitted="' $committedValue '"><id>' $id '</id></delete>';
  793.  
  794.         return $this->delete($rawPost);
  795.     }
  796.  
  797.     /**
  798.      * Create a delete document based on a query and submit it
  799.      *
  800.      * @param string $rawQuery Expected to be utf-8 encoded
  801.      * @param boolean $fromPending 
  802.      * @param boolean $fromCommitted 
  803.      * @return Apache_Solr_Response 
  804.      *
  805.      * @throws Exception If an error occurs during the service call
  806.      */
  807.     public function deleteByQuery($rawQuery$fromPending true$fromCommitted true)
  808.     {
  809.         $pendingValue $fromPending 'true' 'false';
  810.         $committedValue $fromCommitted 'true' 'false';
  811.  
  812.         // escape special xml characters
  813.         $rawQuery htmlspecialchars($rawQueryENT_NOQUOTES'UTF-8');
  814.  
  815.         $rawPost '<delete fromPending="' $pendingValue '" fromCommitted="' $committedValue '"><query>' $rawQuery '</query></delete>';
  816.  
  817.         return $this->delete($rawPost);
  818.     }
  819.  
  820.     /**
  821.      * Send an optimize command.  Will be synchronous unless both wait parameters are set
  822.      * to false.
  823.      *
  824.      * @param boolean $waitFlush 
  825.      * @param boolean $waitSearcher 
  826.      * @param float $timeout Maximum expected duration of the commit operation on the server (otherwise, will throw a communication exception)
  827.      * @return Apache_Solr_Response 
  828.      *
  829.      * @throws Exception If an error occurs during the service call
  830.      */
  831.     public function optimize($waitFlush true$waitSearcher true$timeout 3600)
  832.     {
  833.         $flushValue $waitFlush 'true' 'false';
  834.         $searcherValue $waitSearcher 'true' 'false';
  835.  
  836.         $rawPost '<optimize waitFlush="' $flushValue '" waitSearcher="' $searcherValue '" />';
  837.  
  838.         return $this->_sendRawPost($this->_updateUrl$rawPost$timeout);
  839.     }
  840.  
  841.     /**
  842.      * Simple Search interface
  843.      *
  844.      * @param string $query The raw query string
  845.      * @param int $offset The starting offset for result documents
  846.      * @param int $limit The maximum number of result documents to return
  847.      * @param array $params key / value pairs for other query parameters (see Solr documentation), use arrays for parameter keys used more than once (e.g. facet.field)
  848.      * @return Apache_Solr_Response 
  849.      *
  850.      * @throws Exception If an error occurs during the service call
  851.      */
  852.     public function search($query$offset 0$limit 10$params array())
  853.     {
  854.         if (!is_array($params))
  855.         {
  856.             $params array();
  857.         }
  858.  
  859.         // construct our full parameters
  860.         // sending the version is important in case the format changes
  861.         $params['version'self::SOLR_VERSION;
  862.  
  863.         // common parameters in this interface
  864.         $params['wt'self::SOLR_WRITER;
  865.         $params['json.nl'$this->_namedListTreatment;
  866.  
  867.         $params['q'$query;
  868.         $params['start'$offset;
  869.         $params['rows'$limit;
  870.  
  871.         // use http_build_query to encode our arguments because its faster
  872.         // than urlencoding all the parts ourselves in a loop
  873.         $queryString http_build_query($paramsnull$this->_queryStringDelimiter);
  874.  
  875.         // because http_build_query treats arrays differently than we want to, correct the query
  876.         // string by changing foo[#]=bar (# being an actual number) parameter strings to just
  877.         // multiple foo=bar strings. This regex should always work since '=' will be urlencoded
  878.         // anywhere else the regex isn't expecting it
  879.         $queryString preg_replace('/%5B(?:[0-9]|[1-9][0-9]+)%5D=/''='$queryString);
  880.  
  881.         return $this->_sendRawGet($this->_searchUrl . $this->_queryDelimiter . $queryString);
  882.     }
  883. }

Documentation generated on Tue, 02 Sep 2008 10:45:05 -0400 by phpDocumentor 1.4.0