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 '2.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.      * Servlet mappings
  77.      */
  78.     const PING_SERVLET 'admin/ping';
  79.     const UPDATE_SERVLET 'update';
  80.     const SEARCH_SERVLET 'select';
  81.     const THREADS_SERVLET 'admin/threads';
  82.  
  83.     /**
  84.      * Server identification strings
  85.      *
  86.      * @var string 
  87.      */
  88.     private $_host$_port$_path;
  89.  
  90.     /**
  91.      * Query delimiters. Someone might want to be able to change
  92.      * these (to use &amp; instead of & for example), so I've provided them.
  93.      *
  94.      * @var string 
  95.      */
  96.     private $_queryDelimiter '?'$_queryStringDelimiter '&';
  97.  
  98.     /**
  99.      * Constructed servlet full path URLs
  100.      *
  101.      * @var string 
  102.      */
  103.     private $_updateUrl$_searchUrl$_threadsUrl;
  104.  
  105.     /**
  106.      * Keep track of whether our URLs have been constructed
  107.      *
  108.      * @var boolean 
  109.      */
  110.     private $_urlsInited false;
  111.  
  112.     /**
  113.      * Stream context for posting
  114.      *
  115.      * @var resource 
  116.      */
  117.     private $_postContext;
  118.  
  119.     /**
  120.      * Escape a value for special query characters such as ':', '(', ')', '*', '?', etc.
  121.      *
  122.      * NOTE: inside a phrase fewer characters need escaped, use {@link Apache_Solr_Service::escapePhrase()} instead
  123.      *
  124.      * @param string $value 
  125.      * @return string 
  126.      */
  127.     static public function escape($value)
  128.     {
  129.         //list taken from http://lucene.apache.org/java/docs/queryparsersyntax.html#Escaping%20Special%20Characters
  130.         $pattern '/(\+|-|&&|\|\||!|\(|\)|\{|}|\[|]|\^|"|~|\*|\?|:|\\\)/';
  131.         $replace '\\\$1';
  132.  
  133.         return preg_replace($pattern$replace$value);
  134.     }
  135.  
  136.     /**
  137.      * Escape a value meant to be contained in a phrase for special query characters
  138.      *
  139.      * @param string $value 
  140.      * @return string 
  141.      */
  142.     static public function escapePhrase($value)
  143.     {
  144.         $pattern '/("|\\\)/';
  145.         $replace '\\\$1';
  146.  
  147.         return preg_replace($pattern$replace$value);
  148.     }
  149.  
  150.     /**
  151.      * Convenience function for creating phrase syntax from a value
  152.      *
  153.      * @param string $value 
  154.      * @return string 
  155.      */
  156.     static public function phrase($value)
  157.     {
  158.         return '"' self::escapePhrase($value'"';
  159.     }
  160.  
  161.     /**
  162.      * Constructor. All parameters are optional and will take on default values
  163.      * if not specified.
  164.      *
  165.      * @param string $host 
  166.      * @param string $port 
  167.      * @param string $path 
  168.      */
  169.     public function __construct($host 'localhost'$port 8180$path '/solr/')
  170.     {
  171.         $this->setHost($host);
  172.         $this->setPort($port);
  173.         $this->setPath($path);
  174.  
  175.         $this->_initUrls();
  176.  
  177.         //set up the stream context for posting with file_get_contents
  178.         $contextOpts array(
  179.             'http' => array(
  180.                 'method' => 'POST',
  181.                 'header' => "Content-Type: text/xml; charset=UTF-8\r\n" //php.net example showed \r\n at the end
  182.             )
  183.         );
  184.  
  185.         $this->_postContext stream_context_create($contextOpts);
  186.     }
  187.  
  188.     /**
  189.      * Return a valid http URL given this server's host, port and path and a provided servlet name
  190.      *
  191.      * @param string $servlet 
  192.      * @return string 
  193.      */
  194.     private function _constructUrl($servlet$params array())
  195.     {
  196.         if (count($params))
  197.         {
  198.             //escape all parameters appropriately for inclusion in the query string
  199.             $escapedParams array();
  200.  
  201.             foreach ($params as $key => $value)
  202.             {
  203.                 $escapedParams[urlencode($key'=' urlencode($value);
  204.             }
  205.  
  206.             $queryString $this->_queryDelimiter implode($this->_queryStringDelimiter$escapedParams);
  207.         }
  208.         else
  209.         {
  210.             $queryString '';
  211.         }
  212.  
  213.         return 'http://' $this->_host ':' $this->_port $this->_path $servlet $queryString;
  214.     }
  215.  
  216.     /**
  217.      * Construct the Full URLs for the three servlets we reference
  218.      */
  219.     private function _initUrls()
  220.     {
  221.         //Initialize our full servlet URLs now that we have server information
  222.         $this->_updateUrl $this->_constructUrl(self::UPDATE_SERVLETarray('wt' => self::SOLR_WRITER ));
  223.         $this->_searchUrl $this->_constructUrl(self::SEARCH_SERVLET);
  224.         $this->_threadsUrl $this->_constructUrl(self::THREADS_SERVLETarray('wt' => self::SOLR_WRITER ));
  225.  
  226.         $this->_urlsInited true;
  227.     }
  228.  
  229.     /**
  230.      * Central method for making a get operation against this Solr Server
  231.      *
  232.      * @param string $url 
  233.      * @return Apache_Solr_Response 
  234.      *
  235.      * @throws Exception If a non 200 response status is returned
  236.      */
  237.     private function _sendRawGet($url)
  238.     {
  239.         //$http_response_header is set by file_get_contents
  240.         $response new Apache_Solr_Response(@file_get_contents($url)$http_response_header);
  241.  
  242.         if ($response->getHttpStatus(!= 200)
  243.         {
  244.             throw new Exception('"' $response->getHttpStatus('" Status: ' $response->getHttpStatusMessage());
  245.         }
  246.  
  247.         return $response;
  248.     }
  249.  
  250.     /**
  251.      * Central method for making a post operation against this Solr Server
  252.      *
  253.      * @param string $url 
  254.      * @param string $rawPost 
  255.      * @param string $contentType 
  256.      * @return Apache_Solr_Response 
  257.      *
  258.      * @throws Exception If a non 200 response status is returned
  259.      */
  260.     private function _sendRawPost($url$rawPost$contentType 'text/xml; charset=UTF-8')
  261.     {
  262.         //ensure content type is correct
  263.         stream_context_set_option($this->_postContext'http''header''Content-Type: ' $contentType"\r\n");
  264.  
  265.         //set the content
  266.         stream_context_set_option($this->_postContext'http''content'$rawPost);
  267.  
  268.         //$http_response_header is set by file_get_contents
  269.         $response new Apache_Solr_Response(@file_get_contents($urlfalse$this->_postContext)$http_response_header);
  270.  
  271.         if ($response->getHttpStatus(!= 200)
  272.         {
  273.             throw new Exception('"' $response->getHttpStatus('" Status: ' $response->getHttpStatusMessage());
  274.         }
  275.  
  276.         return $response;
  277.     }
  278.  
  279.     /**
  280.      * Returns the set host
  281.      *
  282.      * @return string 
  283.      */
  284.     public function getHost()
  285.     {
  286.         return $this->_host;
  287.     }
  288.  
  289.     /**
  290.      * Set the host used. If empty will fallback to constants
  291.      *
  292.      * @param string $host 
  293.      */
  294.     public function setHost($host)
  295.     {
  296.         //Use the provided host or use the default
  297.         if (empty($host))
  298.         {
  299.             throw new Exception('Host parameter is empty');
  300.         }
  301.         else
  302.         {
  303.             $this->_host $host;
  304.         }
  305.  
  306.         if ($this->_urlsInited)
  307.         {
  308.             $this->_initUrls();
  309.         }
  310.     }
  311.  
  312.     /**
  313.      * Get the set port
  314.      *
  315.      * @return integer 
  316.      */
  317.     public function getPort()
  318.     {
  319.         return $this->_port;
  320.     }
  321.  
  322.     /**
  323.      * Set the port used. If empty will fallback to constants
  324.      *
  325.      * @param integer $port 
  326.      */
  327.     public function setPort($port)
  328.     {
  329.         //Use the provided port or use the default
  330.         $port = (int) $port;
  331.  
  332.         if ($port <= 0)
  333.         {
  334.             throw new Exception('Port is not a valid port number')
  335.         }
  336.         else
  337.         {
  338.             $this->_port $port;
  339.         }
  340.  
  341.         if ($this->_urlsInited)
  342.         {
  343.             $this->_initUrls();
  344.         }
  345.     }
  346.  
  347.     /**
  348.      * Get the set path.
  349.      *
  350.      * @return string 
  351.      */
  352.     public function getPath()
  353.     {
  354.         return $this->_path;
  355.     }
  356.  
  357.     /**
  358.      * Set the path used. If empty will fallback to constants
  359.      *
  360.      * @param string $path 
  361.      */
  362.     public function setPath($path)
  363.     {
  364.         $path trim($path'/');
  365.  
  366.         $this->_path '/' $path '/';
  367.  
  368.         if ($this->_urlsInited)
  369.         {
  370.             $this->_initUrls();
  371.         }
  372.     }
  373.  
  374.     /**
  375.      * Set the string used to separate the path form the query string.
  376.      * Defaulted to '?'
  377.      *
  378.      * @param string $queryDelimiter 
  379.      */
  380.     public function setQueryDelimiter($queryDelimiter)
  381.     {
  382.         $this->_queryDelimiter $queryDelimiter;
  383.     }
  384.  
  385.     /**
  386.      * Set the string used to separate the parameters in thequery string
  387.      * Defaulted to '&'
  388.      *
  389.      * @param string $queryStringDelimiter 
  390.      */
  391.     public function setQueryStringDelimiter($queryStringDelimiter)
  392.     {
  393.         $this->_queryStringDelimiter $queryStringDelimiter;
  394.     }
  395.  
  396.     /**
  397.      * Call the /admin/ping servlet, can be used to quickly tell if a connection to the
  398.      * server is able to be made.
  399.      *
  400.      * @param float $timeout maximum time to wait for ping in seconds, -1 for unlimited (default is 5)
  401.      * @return float Actual time taken to ping the server, FALSE if timeout occurs
  402.      */
  403.     public function ping($timeout 5)
  404.     {
  405.         $timeout = (float) $timeout;
  406.  
  407.         if ($timeout <= 0)
  408.         {
  409.             $timeout = -1;
  410.         }
  411.  
  412.         $start microtime(true);
  413.  
  414.         //try to connect to the host with timeout
  415.         $fp fsockopen($this->_host$this->_port$errno$errstr$timeout);
  416.  
  417.         if ($fp)
  418.         {
  419.             //If we have a timeout set, then determine the amount of time we have left
  420.             //in the request and set the stream timeout for the write operation
  421.             if ($timeout 0)
  422.             {
  423.                 //do the calculation
  424.                 $writeTimeout $timeout (microtime(true$start);
  425.  
  426.                 //check if we're out of time
  427.                 if ($writeTimeout <= 0)
  428.                 {
  429.                     return false;
  430.                 }
  431.  
  432.                 //convert to microseconds and set the stream timeout
  433.                 $writeTimeoutInMicroseconds = (int) $writeTimeout 1000000;
  434.                 stream_set_timeout($fp0$writeTimeoutInMicroseconds);
  435.             }
  436.  
  437.             $request =     'HEAD ' $this->_path self::PING_SERVLET ' HTTP/1.1' "\r\n" .
  438.                         'host: ' $this->_host "\r\n" .
  439.                         'Connection: close' "\r\n" .
  440.                         "\r\n";
  441.  
  442.             fwrite($fp$request);
  443.  
  444.             //check the stream meta data to see if we timed out during the operation
  445.             $metaData stream_get_meta_data($fp);
  446.  
  447.             if ($metaData['timeout'])
  448.             {
  449.                 fclose($fp);
  450.                 return false;
  451.             }
  452.  
  453.  
  454.             //if we have a timeout set and have made it this far, determine the amount of time
  455.             //still remaining and set the timeout appropriately before the read operation
  456.             if ($timeout 0)
  457.             {
  458.                 //do the calculation
  459.                 $readTimeout $timeout (microtime(true$start);
  460.  
  461.                 //check if we've run out of time
  462.                 if ($readTimeout <= 0)
  463.                 {
  464.                     return false;
  465.                 }
  466.  
  467.                 //convert to microseconds and set the stream timeout
  468.                 $readTimeoutInMicroseconds $readTimeout 1000000;
  469.                 stream_set_timeout($fp0$readTimeoutInMicroseconds);
  470.             }
  471.  
  472.             $response fread($fp15);
  473.  
  474.             //check the stream meta data to see if we timed out during the operation
  475.             $metaData stream_get_meta_data($fp);
  476.  
  477.             if ($metaData['timeout'])
  478.             {
  479.                 fclose($fp);
  480.                 return false;
  481.             }
  482.  
  483.             //we made it, return the approximate ping time
  484.             return microtime(true$start;
  485.         }
  486.  
  487.         return false;
  488.     }
  489.  
  490.     /**
  491.      * Call the /admin/threads servlet and retrieve information about all threads in the
  492.      * Solr servlet's thread group. Useful for diagnostics.
  493.      *
  494.      * @return Apache_Solr_Response 
  495.      *
  496.      * @throws Exception If an error occurs during the service call
  497.      */
  498.     public function threads()
  499.     {
  500.         return $this->_sendRawGet($this->_threadsUrl);
  501.     }
  502.  
  503.     /**
  504.      * Raw Add Method. Takes a raw post body and sends it to the update service.  Post body
  505.      * should be a complete and well formed "add" xml document.
  506.      *
  507.      * @param string $rawPost 
  508.      * @return Apache_Solr_Response 
  509.      *
  510.      * @throws Exception If an error occurs during the service call
  511.      */
  512.     public function add($rawPost)
  513.     {
  514.         return $this->_sendRawPost($this->_updateUrl$rawPost);
  515.     }
  516.  
  517.     /**
  518.      * Add a Solr Document to the index
  519.      *
  520.      * @param Apache_Solr_Document $document 
  521.      * @param boolean $allowDups 
  522.      * @param boolean $overwritePending 
  523.      * @param boolean $overwriteCommitted 
  524.      * @return Apache_Solr_Response 
  525.      *
  526.      * @throws Exception If an error occurs during the service call
  527.      */
  528.     public function addDocument(Apache_Solr_Document $document$allowDups false$overwritePending true$overwriteCommitted true)
  529.     {
  530.         $dupValue $allowDups 'true' 'false';
  531.         $pendingValue $overwritePending 'true' 'false';
  532.         $committedValue $overwriteCommitted 'true' 'false';
  533.  
  534.         $rawPost '<add allowDups="' $dupValue '" overwritePending="' $pendingValue '" overwriteCommitted="' $committedValue '">';
  535.         $rawPost .= $this->_documentToXmlFragment($document);
  536.         $rawPost .= '</add>';
  537.  
  538.         return $this->add($rawPost);
  539.     }
  540.  
  541.     /**
  542.      * Add an array of Solr Documents to the index all at once
  543.      *
  544.      * @param array $documents Should be an array of Apache_Solr_Document instances
  545.      * @param boolean $allowDups 
  546.      * @param boolean $overwritePending 
  547.      * @param boolean $overwriteCommitted 
  548.      * @return Apache_Solr_Response 
  549.      *
  550.      * @throws Exception If an error occurs during the service call
  551.      */
  552.     public function addDocuments($documents$allowDups false$overwritePending true$overwriteCommitted true)
  553.     {
  554.         $dupValue $allowDups 'true' 'false';
  555.         $pendingValue $overwritePending 'true' 'false';
  556.         $committedValue $overwriteCommitted 'true' 'false';
  557.  
  558.         $rawPost '<add allowDups="' $dupValue '" overwritePending="' $pendingValue '" overwriteCommitted="' $committedValue '">';
  559.  
  560.         foreach ($documents as $document)
  561.         {
  562.             if ($document instanceof Apache_Solr_Document)
  563.             {
  564.                 $rawPost .= $this->_documentToXmlFragment($document);
  565.             }
  566.         }
  567.  
  568.         $rawPost .= '</add>';
  569.  
  570.         return $this->add($rawPost);
  571.     }
  572.  
  573.     /**
  574.      * Create an XML fragment appropriate for use inside a Solr add call
  575.      *
  576.      * @return string 
  577.      */
  578.     private function _documentToXmlFragment(Apache_Solr_Document $document)
  579.     {
  580.         $xml '<doc>';
  581.  
  582.         foreach ($document as $key => $value)
  583.         {
  584.             $key htmlspecialchars($keyENT_QUOTES'UTF-8');
  585.  
  586.             if (is_array($value))
  587.             {
  588.                 foreach ($value as $multivalue)
  589.                 {
  590.                     $multivalue htmlspecialchars($multivalueENT_NOQUOTES'UTF-8');
  591.  
  592.                     $xml .= '<field name="' $key '">' $multivalue '</field>';
  593.                 }
  594.             }
  595.             else
  596.             {
  597.                 $value htmlspecialchars($valueENT_NOQUOTES'UTF-8');
  598.  
  599.                 $xml .= '<field name="' $key '">' $value '</field>';
  600.             }
  601.         }
  602.  
  603.         $xml .= '</doc>';
  604.  
  605.         return $xml;
  606.     }
  607.  
  608.     /**
  609.      * Send a commit command.  Will be synchronous unless both wait parameters are set
  610.      * to false.
  611.      *
  612.      * @param boolean $waitFlush 
  613.      * @param boolean $waitSearcher 
  614.      * @return Apache_Solr_Response 
  615.      *
  616.      * @throws Exception If an error occurs during the service call
  617.      */
  618.     public function commit($waitFlush true$waitSearcher true)
  619.     {
  620.         $flushValue $waitFlush 'true' 'false';
  621.         $searcherValue $waitSearcher 'true' 'false';
  622.  
  623.         $rawPost '<commit waitFlush="' $flushValue '" waitSearcher="' $searcherValue '" />';
  624.  
  625.         return $this->_sendRawPost($this->_updateUrl$rawPost);
  626.     }
  627.  
  628.     /**
  629.      * Raw Delete Method. Takes a raw post body and sends it to the update service. Body should be
  630.      * a complete and well formed "delete" xml document
  631.      *
  632.      * @param string $rawPost 
  633.      * @return Apache_Solr_Response 
  634.      *
  635.      * @throws Exception If an error occurs during the service call
  636.      */
  637.     public function delete($rawPost)
  638.     {
  639.         return $this->_sendRawPost($this->_updateUrl$rawPost);
  640.     }
  641.  
  642.     /**
  643.      * Create a delete document based on document ID
  644.      *
  645.      * @param string $id 
  646.      * @param boolean $fromPending 
  647.      * @param boolean $fromCommitted 
  648.      * @return Apache_Solr_Response 
  649.      *
  650.      * @throws Exception If an error occurs during the service call
  651.      */
  652.     public function deleteById($id$fromPending true$fromCommitted true)
  653.     {
  654.         $pendingValue $fromPending 'true' 'false';
  655.         $committedValue $fromCommitted 'true' 'false';
  656.  
  657.         //escape special xml characters
  658.         $id htmlspecialchars($idENT_NOQUOTES'UTF-8');
  659.  
  660.         $rawPost '<delete fromPending="' $pendingValue '" fromCommitted="' $committedValue '"><id>' $id '</id></delete>';
  661.  
  662.         return $this->delete($rawPost);
  663.     }
  664.  
  665.     /**
  666.      * Create a delete document based on a query and submit it
  667.      *
  668.      * @param string $rawQuery 
  669.      * @param boolean $fromPending 
  670.      * @param boolean $fromCommitted 
  671.      * @return Apache_Solr_Response 
  672.      *
  673.      * @throws Exception If an error occurs during the service call
  674.      */
  675.     public function deleteByQuery($rawQuery$fromPending true$fromCommitted true)
  676.     {
  677.         $pendingValue $fromPending 'true' 'false';
  678.         $committedValue $fromCommitted 'true' 'false';
  679.  
  680.         //escape special xml characters
  681.         $rawQuery htmlspecialchars($rawQueryENT_NOQUOTES'UTF-8');
  682.  
  683.         $rawPost '<delete fromPending="' $pendingValue '" fromCommitted="' $committedValue '"><query>' $rawQuery '</query></delete>';
  684.  
  685.         return $this->delete($rawPost);
  686.     }
  687.  
  688.     /**
  689.      * Send an optimize command.  Will be synchronous unless both wait parameters are set
  690.      * to false.
  691.      *
  692.      * @param boolean $waitFlush 
  693.      * @param boolean $waitSearcher 
  694.      * @return Apache_Solr_Response 
  695.      *
  696.      * @throws Exception If an error occurs during the service call
  697.      */
  698.     public function optimize($waitFlush true$waitSearcher true)
  699.     {
  700.         $flushValue $waitFlush 'true' 'false';
  701.         $searcherValue $waitSearcher 'true' 'false';
  702.  
  703.         $rawPost '<optimize waitFlush="' $flushValue '" waitSearcher="' $searcherValue '" />';
  704.  
  705.         return $this->_sendRawPost($this->_updateUrl$rawPost);
  706.     }
  707.  
  708.     /**
  709.      * Simple Search interface
  710.      *
  711.      * @param string $query The raw query string
  712.      * @param int $offset The starting offset for result documents
  713.      * @param int $limit The maximum number of result documents to return
  714.      * @param array $params key / value pairs for query parameters, use arrays for multivalued parameters
  715.      * @return Apache_Solr_Response 
  716.      *
  717.      * @throws Exception If an error occurs during the service call
  718.      */
  719.     public function search($query$offset 0$limit 10$params array())
  720.     {
  721.         if (!is_array($params))
  722.         {
  723.             $params array();
  724.         }
  725.  
  726.         //construct our full parameters
  727.         //sending the version is important in case the format changes
  728.         $params['version'self::SOLR_VERSION;
  729.  
  730.         //common parameters in this interface
  731.         $params['wt'self::SOLR_WRITER;
  732.         $params['q'$query;
  733.         $params['start'$offset;
  734.         $params['rows'$limit;
  735.  
  736.         //escape all parameters appropriately for inclusion in the GET parameters
  737.         $escapedParams array();
  738.  
  739.         do
  740.         {
  741.             //because some parameters can be included multiple times, loop through all
  742.             //params and include their value or their first array value. unset values as
  743.             //they are fully added so that the params list can be iteratively added.
  744.             //
  745.             //NOTE: could be done all at once, but this way makes the query string more
  746.             //readable at little performance cost
  747.             foreach ($params as $key => &$value)
  748.             {
  749.                 if (is_array($value))
  750.                 {
  751.                     //parameter has multiple values that need passed
  752.                     //array_shift pops off the first value in the array and also removes it
  753.                     $escapedParams[urlencode($key'=' urlencode(array_shift($value));
  754.  
  755.                     if (empty($value))
  756.                     {
  757.                         unset($params[$key]);
  758.                     }
  759.                 }
  760.                 else
  761.                 {
  762.                     //simple, single value case
  763.                     $escapedParams[urlencode($key'=' urlencode($value);
  764.                     unset($params[$key]);
  765.                 }
  766.             }
  767.         while (!empty($params));
  768.  
  769.         return $this->_sendRawGet($this->_searchUrl $this->_queryDelimiter implode($this->_queryStringDelimiter$escapedParams));
  770.     }
  771. }

Documentation generated on Tue, 02 Oct 2007 12:55:39 -0400 by phpDocumentor 1.4.0