Source for file Service.php

Documentation is available at Service.php

  1. <?php
  2. /**
  3.  * Copyright (c) 2007-2011, Servigistics, Inc.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions are met:
  8.  *
  9.  *  - Redistributions of source code must retain the above copyright notice,
  10.  *    this list of conditions and the following disclaimer.
  11.  *  - Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in the
  13.  *    documentation and/or other materials provided with the distribution.
  14.  *  - Neither the name of Servigistics, Inc. nor the names of
  15.  *    its contributors may be used to endorse or promote products derived from
  16.  *    this software without specific prior written permission.
  17.  *
  18.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  19.  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  20.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  21.  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  22.  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  23.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  24.  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  25.  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  26.  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  27.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  28.  * POSSIBILITY OF SUCH DAMAGE.
  29.  *
  30.  * @copyright Copyright 2007-2011 Servigistics, Inc. (http://servigistics.com)
  31.  * @license http://solr-php-client.googlecode.com/svn/trunk/COPYING New BSD
  32.  * @version $Id: Service.php 59 2011-02-08 20:38:59Z donovan.jimenez $
  33.  *
  34.  * @package Apache
  35.  * @subpackage Solr
  36.  * @author Donovan Jimenez <djimenez@conduit-it.com>
  37.  */
  38.  
  39. // See Issue #1 (http://code.google.com/p/solr-php-client/issues/detail?id=1)
  40. // Doesn't follow typical include path conventions, but is more convenient for users
  41. require_once(dirname(__FILE__'/Exception.php');
  42. require_once(dirname(__FILE__'/HttpTransportException.php');
  43. require_once(dirname(__FILE__'/InvalidArgumentException.php');
  44.  
  45. require_once(dirname(__FILE__'/Document.php');
  46. require_once(dirname(__FILE__'/Response.php');
  47.  
  48. require_once(dirname(__FILE__'/HttpTransport/Interface.php');
  49.  
  50. /**
  51.  * Starting point for the Solr API. Represents a Solr server resource and has
  52.  * methods for pinging, adding, deleting, committing, optimizing and searching.
  53.  *
  54.  * Example Usage:
  55.  * <code>
  56.  * ...
  57.  * $solr = new Apache_Solr_Service(); //or explicitly new Apache_Solr_Service('localhost', 8180, '/solr')
  58.  *
  59.  * if ($solr->ping())
  60.  * {
  61.  *         $solr->deleteByQuery('*:*'); //deletes ALL documents - be careful :)
  62.  *
  63.  *         $document = new Apache_Solr_Document();
  64.  *         $document->id = uniqid(); //or something else suitably unique
  65.  *
  66.  *         $document->title = 'Some Title';
  67.  *         $document->content = 'Some content for this wonderful document. Blah blah blah.';
  68.  *
  69.  *         $solr->addDocument($document);     //if you're going to be adding documents in bulk using addDocuments
  70.  *                                         //with an array of documents is faster
  71.  *
  72.  *         $solr->commit(); //commit to see the deletes and the document
  73.  *         $solr->optimize(); //merges multiple segments into one
  74.  *
  75.  *         //and the one we all care about, search!
  76.  *         //any other common or custom parameters to the request handler can go in the
  77.  *         //optional 4th array argument.
  78.  *         $solr->search('content:blah', 0, 10, array('sort' => 'timestamp desc'));
  79.  * }
  80.  * ...
  81.  * </code>
  82.  *
  83.  * @todo Investigate using other HTTP clients other than file_get_contents built-in handler. Could provide performance
  84.  *  improvements when dealing with multiple requests by using HTTP's keep alive functionality
  85.  */
  86. {
  87.     /**
  88.      * SVN Revision meta data for this class
  89.      */
  90.     const SVN_REVISION '$Revision: 59 $';
  91.  
  92.     /**
  93.      * SVN ID meta data for this class
  94.      */
  95.     const SVN_ID '$Id: Service.php 59 2011-02-08 20:38:59Z donovan.jimenez $';
  96.  
  97.     /**
  98.      * Response writer we'll request - JSON. See http://code.google.com/p/solr-php-client/issues/detail?id=6#c1 for reasoning
  99.      */
  100.     const SOLR_WRITER 'json';
  101.  
  102.     /**
  103.      * NamedList Treatment constants
  104.      */
  105.     const NAMED_LIST_FLAT 'flat';
  106.     const NAMED_LIST_MAP 'map';
  107.  
  108.     /**
  109.      * Search HTTP Methods
  110.      */
  111.     const METHOD_GET 'GET';
  112.     const METHOD_POST 'POST';
  113.  
  114.     /**
  115.      * Servlet mappings
  116.      */
  117.     const PING_SERVLET 'admin/ping';
  118.     const UPDATE_SERVLET 'update';
  119.     const SEARCH_SERVLET 'select';
  120.     const THREADS_SERVLET 'admin/threads';
  121.     const EXTRACT_SERVLET 'update/extract';
  122.  
  123.     /**
  124.      * Server identification strings
  125.      *
  126.      * @var string 
  127.      */
  128.     protected $_host$_port$_path;
  129.  
  130.     /**
  131.      * Whether {@link Apache_Solr_Response} objects should create {@link Apache_Solr_Document}s in
  132.      * the returned parsed data
  133.      *
  134.      * @var boolean 
  135.      */
  136.     protected $_createDocuments = true;
  137.  
  138.     /**
  139.      * Whether {@link Apache_Solr_Response} objects should have multivalue fields with only a single value
  140.      * collapsed to appear as a single value would.
  141.      *
  142.      * @var boolean 
  143.      */
  144.     protected $_collapseSingleValueArrays = true;
  145.  
  146.     /**
  147.      * How NamedLists should be formatted in the output.  This specifically effects facet counts. Valid values
  148.      * are {@link Apache_Solr_Service::NAMED_LIST_MAP} (default) or {@link Apache_Solr_Service::NAMED_LIST_FLAT}.
  149.      *
  150.      * @var string 
  151.      */
  152.     protected $_namedListTreatment = self::NAMED_LIST_MAP;
  153.  
  154.     /**
  155.      * Query delimiters. Someone might want to be able to change
  156.      * these (to use &amp; instead of & for example), so I've provided them.
  157.      *
  158.      * @var string 
  159.      */
  160.     protected $_queryDelimiter = '?'$_queryStringDelimiter = '&'$_queryBracketsEscaped = true;
  161.  
  162.     /**
  163.      * Constructed servlet full path URLs
  164.      *
  165.      * @var string 
  166.      */
  167.     protected $_pingUrl$_updateUrl$_searchUrl$_threadsUrl;
  168.  
  169.     /**
  170.      * Keep track of whether our URLs have been constructed
  171.      *
  172.      * @var boolean 
  173.      */
  174.     protected $_urlsInited = false;
  175.  
  176.     /**
  177.      * HTTP Transport implementation (pluggable)
  178.      *
  179.      * @var Apache_Solr_HttpTransport_Interface 
  180.      */
  181.     protected $_httpTransport = false;
  182.  
  183.     /**
  184.      * Escape a value for special query characters such as ':', '(', ')', '*', '?', etc.
  185.      *
  186.      * NOTE: inside a phrase fewer characters need escaped, use {@link Apache_Solr_Service::escapePhrase()} instead
  187.      *
  188.      * @param string $value 
  189.      * @return string 
  190.      */
  191.     static public function escape($value)
  192.     {
  193.         //list taken from http://lucene.apache.org/java/docs/queryparsersyntax.html#Escaping%20Special%20Characters
  194.         $pattern '/(\+|-|&&|\|\||!|\(|\)|\{|}|\[|]|\^|"|~|\*|\?|:|\\\)/';
  195.         $replace '\\\$1';
  196.  
  197.         return preg_replace($pattern$replace$value);
  198.     }
  199.  
  200.     /**
  201.      * Escape a value meant to be contained in a phrase for special query characters
  202.      *
  203.      * @param string $value 
  204.      * @return string 
  205.      */
  206.     static public function escapePhrase($value)
  207.     {
  208.         $pattern '/("|\\\)/';
  209.         $replace '\\\$1';
  210.  
  211.         return preg_replace($pattern$replace$value);
  212.     }
  213.  
  214.     /**
  215.      * Convenience function for creating phrase syntax from a value
  216.      *
  217.      * @param string $value 
  218.      * @return string 
  219.      */
  220.     static public function phrase($value)
  221.     {
  222.         return '"' self::escapePhrase($value'"';
  223.     }
  224.  
  225.     /**
  226.      * Constructor. All parameters are optional and will take on default values
  227.      * if not specified.
  228.      *
  229.      * @param string $host 
  230.      * @param string $port 
  231.      * @param string $path 
  232.      * @param Apache_Solr_HttpTransport_Interface $httpTransport 
  233.      */
  234.     public function __construct($host 'localhost'$port 8180$path '/solr/'$httpTransport false)
  235.     {
  236.         $this->setHost($host);
  237.         $this->setPort($port);
  238.         $this->setPath($path);
  239.  
  240.         $this->_initUrls();
  241.  
  242.         if ($httpTransport)
  243.         {
  244.             $this->setHttpTransport($httpTransport);
  245.         }
  246.  
  247.         // check that our php version is >= 5.1.3 so we can correct for http_build_query behavior later
  248.         $this->_queryBracketsEscaped = version_compare(phpversion()'5.1.3''>=');
  249.     }
  250.  
  251.     /**
  252.      * Return a valid http URL given this server's host, port and path and a provided servlet name
  253.      *
  254.      * @param string $servlet 
  255.      * @return string 
  256.      */
  257.     protected function _constructUrl($servlet$params array())
  258.     {
  259.         if (count($params))
  260.         {
  261.             //escape all parameters appropriately for inclusion in the query string
  262.             $escapedParams array();
  263.  
  264.             foreach ($params as $key => $value)
  265.             {
  266.                 $escapedParams[urlencode($key'=' urlencode($value);
  267.             }
  268.  
  269.             $queryString $this->_queryDelimiter . implode($this->_queryStringDelimiter$escapedParams);
  270.         }
  271.         else
  272.         {
  273.             $queryString '';
  274.         }
  275.  
  276.         return 'http://' $this->_host . ':' $this->_port . $this->_path . $servlet $queryString;
  277.     }
  278.  
  279.     /**
  280.      * Construct the Full URLs for the three servlets we reference
  281.      */
  282.     protected function _initUrls()
  283.     {
  284.         //Initialize our full servlet URLs now that we have server information
  285.         $this->_extractUrl $this->_constructUrl(self::EXTRACT_SERVLET);
  286.         $this->_pingUrl = $this->_constructUrl(self::PING_SERVLET);
  287.         $this->_searchUrl = $this->_constructUrl(self::SEARCH_SERVLET);
  288.         $this->_threadsUrl = $this->_constructUrl(self::THREADS_SERVLETarray('wt' => self::SOLR_WRITER ));
  289.         $this->_updateUrl = $this->_constructUrl(self::UPDATE_SERVLETarray('wt' => self::SOLR_WRITER ));
  290.  
  291.         $this->_urlsInited = true;
  292.     }
  293.  
  294.     protected function _generateQueryString($params)
  295.     {
  296.         // use http_build_query to encode our arguments because its faster
  297.         // than urlencoding all the parts ourselves in a loop
  298.         //
  299.         // because http_build_query treats arrays differently than we want to, correct the query
  300.         // string by changing foo[#]=bar (# being an actual number) parameter strings to just
  301.         // multiple foo=bar strings. This regex should always work since '=' will be urlencoded
  302.         // anywhere else the regex isn't expecting it
  303.         //
  304.         // NOTE: before php 5.1.3 brackets were not url encoded by http_build query - we've checked
  305.         // the php version in the constructor and put the results in the instance variable. Also, before
  306.         // 5.1.2 the arg_separator parameter was not available, so don't use it
  307.         if ($this->_queryBracketsEscaped)
  308.         {
  309.             $queryString http_build_query($paramsnull$this->_queryStringDelimiter);
  310.             return preg_replace('/%5B(?:[0-9]|[1-9][0-9]+)%5D=/''='$queryString);
  311.         }
  312.         else
  313.         {
  314.             $queryString http_build_query($params);
  315.             return preg_replace('/\\[(?:[0-9]|[1-9][0-9]+)\\]=/''='$queryString);
  316.         }
  317.     }
  318.  
  319.     /**
  320.      * Central method for making a get operation against this Solr Server
  321.      *
  322.      * @param string $url 
  323.      * @param float $timeout Read timeout in seconds
  324.      * @return Apache_Solr_Response 
  325.      *
  326.      * @throws Apache_Solr_HttpTransportException If a non 200 response status is returned
  327.      */
  328.     protected function _sendRawGet($url$timeout FALSE)
  329.     {
  330.         $httpTransport $this->getHttpTransport();
  331.  
  332.         $httpResponse $httpTransport->performGetRequest($url$timeout);
  333.         $solrResponse new Apache_Solr_Response($httpResponse$this->_createDocuments$this->_collapseSingleValueArrays);
  334.  
  335.         if ($solrResponse->getHttpStatus(!= 200)
  336.         {
  337.             throw new Apache_Solr_HttpTransportException($solrResponse);
  338.         }
  339.  
  340.         return $solrResponse;
  341.     }
  342.  
  343.     /**
  344.      * Central method for making a post operation against this Solr Server
  345.      *
  346.      * @param string $url 
  347.      * @param string $rawPost 
  348.      * @param float $timeout Read timeout in seconds
  349.      * @param string $contentType 
  350.      * @return Apache_Solr_Response 
  351.      *
  352.      * @throws Apache_Solr_HttpTransportException If a non 200 response status is returned
  353.      */
  354.     protected function _sendRawPost($url$rawPost$timeout FALSE$contentType 'text/xml; charset=UTF-8')
  355.     {
  356.         $httpTransport $this->getHttpTransport();
  357.  
  358.         $httpResponse $httpTransport->performPostRequest($url$rawPost$contentType$timeout);
  359.         $solrResponse new Apache_Solr_Response($httpResponse$this->_createDocuments$this->_collapseSingleValueArrays);
  360.  
  361.         if ($solrResponse->getHttpStatus(!= 200)
  362.         {
  363.             throw new Apache_Solr_HttpTransportException($solrResponse);
  364.         }
  365.  
  366.         return $solrResponse;
  367.     }
  368.  
  369.     /**
  370.      * Returns the set host
  371.      *
  372.      * @return string 
  373.      */
  374.     public function getHost()
  375.     {
  376.         return $this->_host;
  377.     }
  378.  
  379.     /**
  380.      * Set the host used. If empty will fallback to constants
  381.      *
  382.      * @param string $host 
  383.      *
  384.      * @throws Apache_Solr_InvalidArgumentException If the host parameter is empty
  385.      */
  386.     public function setHost($host)
  387.     {
  388.         //Use the provided host or use the default
  389.         if (empty($host))
  390.         {
  391.             throw new Apache_Solr_InvalidArgumentException('Host parameter is empty');
  392.         }
  393.         else
  394.         {
  395.             $this->_host = $host;
  396.         }
  397.  
  398.         if ($this->_urlsInited)
  399.         {
  400.             $this->_initUrls();
  401.         }
  402.     }
  403.  
  404.     /**
  405.      * Get the set port
  406.      *
  407.      * @return integer 
  408.      */
  409.     public function getPort()
  410.     {
  411.         return $this->_port;
  412.     }
  413.  
  414.     /**
  415.      * Set the port used. If empty will fallback to constants
  416.      *
  417.      * @param integer $port 
  418.      *
  419.      * @throws Apache_Solr_InvalidArgumentException If the port parameter is empty
  420.      */
  421.     public function setPort($port)
  422.     {
  423.         //Use the provided port or use the default
  424.         $port = (int) $port;
  425.  
  426.         if ($port <= 0)
  427.         {
  428.             throw new Apache_Solr_InvalidArgumentException('Port is not a valid port number');
  429.         }
  430.         else
  431.         {
  432.             $this->_port = $port;
  433.         }
  434.  
  435.         if ($this->_urlsInited)
  436.         {
  437.             $this->_initUrls();
  438.         }
  439.     }
  440.  
  441.     /**
  442.      * Get the set path.
  443.      *
  444.      * @return string 
  445.      */
  446.     public function getPath()
  447.     {
  448.         return $this->_path;
  449.     }
  450.  
  451.     /**
  452.      * Set the path used. If empty will fallback to constants
  453.      *
  454.      * @param string $path 
  455.      */
  456.     public function setPath($path)
  457.     {
  458.         $path trim($path'/');
  459.  
  460.         $this->_path = '/' $path '/';
  461.  
  462.         if ($this->_urlsInited)
  463.         {
  464.             $this->_initUrls();
  465.         }
  466.     }
  467.  
  468.     /**
  469.      * Get the current configured HTTP Transport
  470.      *
  471.      * @return HttpTransportInterface 
  472.      */
  473.     public function getHttpTransport()
  474.     {
  475.         // lazy load a default if one has not be set
  476.         if ($this->_httpTransport === false)
  477.         {
  478.             require_once(dirname(__FILE__'/HttpTransport/FileGetContents.php');
  479.  
  480.             $this->_httpTransport = new Apache_Solr_HttpTransport_FileGetContents();
  481.         }
  482.  
  483.         return $this->_httpTransport;
  484.     }
  485.  
  486.     /**
  487.      * Set the HTTP Transport implemenation that will be used for all HTTP requests
  488.      *
  489.      * @param Apache_Solr_HttpTransport_Interface 
  490.      */
  491.     public function setHttpTransport(Apache_Solr_HttpTransport_Interface $httpTransport)
  492.     {
  493.         $this->_httpTransport = $httpTransport;
  494.     }
  495.  
  496.     /**
  497.      * Set the create documents flag. This determines whether {@link Apache_Solr_Response} objects will
  498.      * parse the response and create {@link Apache_Solr_Document} instances in place.
  499.      *
  500.      * @param boolean $createDocuments 
  501.      */
  502.     public function setCreateDocuments($createDocuments)
  503.     {
  504.         $this->_createDocuments = (bool) $createDocuments;
  505.     }
  506.  
  507.     /**
  508.      * Get the current state of teh create documents flag.
  509.      *
  510.      * @return boolean 
  511.      */
  512.     public function getCreateDocuments()
  513.     {
  514.         return $this->_createDocuments;
  515.     }
  516.  
  517.     /**
  518.      * Set the collapse single value arrays flag.
  519.      *
  520.      * @param boolean $collapseSingleValueArrays 
  521.      */
  522.     public function setCollapseSingleValueArrays($collapseSingleValueArrays)
  523.     {
  524.         $this->_collapseSingleValueArrays = (bool) $collapseSingleValueArrays;
  525.     }
  526.  
  527.     /**
  528.      * Get the current state of the collapse single value arrays flag.
  529.      *
  530.      * @return boolean 
  531.      */
  532.     public function getCollapseSingleValueArrays()
  533.     {
  534.         return $this->_collapseSingleValueArrays;
  535.     }
  536.  
  537.     /**
  538.      * Get the current default timeout setting (initially the default_socket_timeout ini setting)
  539.      * in seconds
  540.      *
  541.      * @return float 
  542.      *
  543.      * @deprecated Use the getDefaultTimeout method on the HTTP transport implementation
  544.      */
  545.     public function getDefaultTimeout()
  546.     {
  547.         return $this->getHttpTransport()->getDefaultTimeout();
  548.     }
  549.  
  550.     /**
  551.      * Set the default timeout for all calls that aren't passed a specific timeout
  552.      *
  553.      * @param float $timeout Timeout value in seconds
  554.      *
  555.      * @deprecated Use the setDefaultTimeout method on the HTTP transport implementation
  556.      */
  557.     public function setDefaultTimeout($timeout)
  558.     {
  559.         $this->getHttpTransport()->setDefaultTimeout($timeout);
  560.     }
  561.  
  562.     /**
  563.      * Set how NamedLists should be formatted in the response data. This mainly effects
  564.      * the facet counts format.
  565.      *
  566.      * @param string $namedListTreatment 
  567.      * @throws Apache_Solr_InvalidArgumentException If invalid option is set
  568.      */
  569.     public function setNamedListTreatment($namedListTreatment)
  570.     {
  571.         switch ((string) $namedListTreatment)
  572.         {
  573.             case Apache_Solr_Service::NAMED_LIST_FLAT:
  574.                 $this->_namedListTreatment = Apache_Solr_Service::NAMED_LIST_FLAT;
  575.                 break;
  576.  
  577.             case Apache_Solr_Service::NAMED_LIST_MAP:
  578.                 $this->_namedListTreatment = Apache_Solr_Service::NAMED_LIST_MAP;
  579.                 break;
  580.  
  581.             default:
  582.                 throw new Apache_Solr_InvalidArgumentException('Not a valid named list treatement option');
  583.         }
  584.     }
  585.  
  586.     /**
  587.      * Get the current setting for named list treatment.
  588.      *
  589.      * @return string 
  590.      */
  591.     public function getNamedListTreatment()
  592.     {
  593.         return $this->_namedListTreatment;
  594.     }
  595.  
  596.     /**
  597.      * Set the string used to separate the path form the query string.
  598.      * Defaulted to '?'
  599.      *
  600.      * @param string $queryDelimiter 
  601.      */
  602.     public function setQueryDelimiter($queryDelimiter)
  603.     {
  604.         $this->_queryDelimiter = $queryDelimiter;
  605.     }
  606.  
  607.     /**
  608.      * Set the string used to separate the parameters in thequery string
  609.      * Defaulted to '&'
  610.      *
  611.      * @param string $queryStringDelimiter 
  612.      */
  613.     public function setQueryStringDelimiter($queryStringDelimiter)
  614.     {
  615.         $this->_queryStringDelimiter = $queryStringDelimiter;
  616.     }
  617.  
  618.     /**
  619.      * Call the /admin/ping servlet, can be used to quickly tell if a connection to the
  620.      * server is able to be made.
  621.      *
  622.      * @param float $timeout maximum time to wait for ping in seconds, -1 for unlimited (default is 2)
  623.      * @return float Actual time taken to ping the server, FALSE if timeout or HTTP error status occurs
  624.      */
  625.     public function ping($timeout 2)
  626.     {
  627.         $start microtime(true);
  628.         
  629.         $httpTransport $this->getHttpTransport();
  630.  
  631.         $httpResponse $httpTransport->performHeadRequest($this->_pingUrl$timeout);
  632.         $solrResponse new Apache_Solr_Response($httpResponse$this->_createDocuments$this->_collapseSingleValueArrays);
  633.  
  634.         if ($solrResponse->getHttpStatus(== 200)
  635.         {
  636.             return microtime(true$start;
  637.         }
  638.         else
  639.         {
  640.             return false;
  641.         }
  642.     }
  643.  
  644.     /**
  645.      * Call the /admin/threads servlet and retrieve information about all threads in the
  646.      * Solr servlet's thread group. Useful for diagnostics.
  647.      *
  648.      * @return Apache_Solr_Response 
  649.      *
  650.      * @throws Apache_Solr_HttpTransportException If an error occurs during the service call
  651.      */
  652.     public function threads()
  653.     {
  654.         return $this->_sendRawGet($this->_threadsUrl);
  655.     }
  656.  
  657.     /**
  658.      * Raw Add Method. Takes a raw post body and sends it to the update service.  Post body
  659.      * should be a complete and well formed "add" xml document.
  660.      *
  661.      * @param string $rawPost 
  662.      * @return Apache_Solr_Response 
  663.      *
  664.      * @throws Apache_Solr_HttpTransportException If an error occurs during the service call
  665.      */
  666.     public function add($rawPost)
  667.     {
  668.         return $this->_sendRawPost($this->_updateUrl$rawPost);
  669.     }
  670.  
  671.     /**
  672.      * Add a Solr Document to the index
  673.      *
  674.      * @param Apache_Solr_Document $document 
  675.      * @param boolean $allowDups 
  676.      * @param boolean $overwritePending 
  677.      * @param boolean $overwriteCommitted 
  678.      * @param integer $commitWithin The number of milliseconds that a document must be committed within, see @{link http://wiki.apache.org/solr/UpdateXmlMessages#The_Update_Schema} for details.  If left empty this property will not be set in the request.
  679.      * @return Apache_Solr_Response 
  680.      *
  681.      * @throws Apache_Solr_HttpTransportException If an error occurs during the service call
  682.      */
  683.     public function addDocument(Apache_Solr_Document $document$allowDups false$overwritePending true$overwriteCommitted true$commitWithin 0)
  684.     {
  685.         $dupValue $allowDups 'true' 'false';
  686.         $pendingValue $overwritePending 'true' 'false';
  687.         $committedValue $overwriteCommitted 'true' 'false';
  688.         
  689.         $commitWithin = (int) $commitWithin;
  690.         $commitWithinString $commitWithin " commitWithin=\"{$commitWithin}\"'';
  691.         
  692.         $rawPost "<add allowDups=\"{$dupValue}\" overwritePending=\"{$pendingValue}\" overwriteCommitted=\"{$committedValue}\"{$commitWithinString}>";
  693.         $rawPost .= $this->_documentToXmlFragment($document);
  694.         $rawPost .= '</add>';
  695.  
  696.         return $this->add($rawPost);
  697.     }
  698.  
  699.     /**
  700.      * Add an array of Solr Documents to the index all at once
  701.      *
  702.      * @param array $documents Should be an array of Apache_Solr_Document instances
  703.      * @param boolean $allowDups 
  704.      * @param boolean $overwritePending 
  705.      * @param boolean $overwriteCommitted 
  706.      * @param integer $commitWithin The number of milliseconds that a document must be committed within, see @{link http://wiki.apache.org/solr/UpdateXmlMessages#The_Update_Schema} for details.  If left empty this property will not be set in the request.
  707.      * @return Apache_Solr_Response 
  708.      *
  709.      * @throws Apache_Solr_HttpTransportException If an error occurs during the service call
  710.      */
  711.     public function addDocuments($documents$allowDups false$overwritePending true$overwriteCommitted true$commitWithin 0)
  712.     {
  713.         $dupValue $allowDups 'true' 'false';
  714.         $pendingValue $overwritePending 'true' 'false';
  715.         $committedValue $overwriteCommitted 'true' 'false';
  716.  
  717.         $commitWithin = (int) $commitWithin;
  718.         $commitWithinString $commitWithin " commitWithin=\"{$commitWithin}\"'';
  719.  
  720.         $rawPost "<add allowDups=\"{$dupValue}\" overwritePending=\"{$pendingValue}\" overwriteCommitted=\"{$committedValue}\"{$commitWithinString}>";
  721.  
  722.         foreach ($documents as $document)
  723.         {
  724.             if ($document instanceof Apache_Solr_Document)
  725.             {
  726.                 $rawPost .= $this->_documentToXmlFragment($document);
  727.             }
  728.         }
  729.  
  730.         $rawPost .= '</add>';
  731.  
  732.         return $this->add($rawPost);
  733.     }
  734.  
  735.     /**
  736.      * Create an XML fragment from a {@link Apache_Solr_Document} instance appropriate for use inside a Solr add call
  737.      *
  738.      * @return string 
  739.      */
  740.     protected function _documentToXmlFragment(Apache_Solr_Document $document)
  741.     {
  742.         $xml '<doc';
  743.  
  744.         if ($document->getBoost(!== false)
  745.         {
  746.             $xml .= ' boost="' $document->getBoost('"';
  747.         }
  748.  
  749.         $xml .= '>';
  750.  
  751.         foreach ($document as $key => $value)
  752.         {
  753.             $key htmlspecialchars($keyENT_QUOTES'UTF-8');
  754.             $fieldBoost $document->getFieldBoost($key);
  755.  
  756.             if (is_array($value))
  757.             {
  758.                 foreach ($value as $multivalue)
  759.                 {
  760.                     $xml .= '<field name="' $key '"';
  761.  
  762.                     if ($fieldBoost !== false)
  763.                     {
  764.                         $xml .= ' boost="' $fieldBoost '"';
  765.  
  766.                         // only set the boost for the first field in the set
  767.                         $fieldBoost false;
  768.                     }
  769.  
  770.                     $multivalue htmlspecialchars($multivalueENT_NOQUOTES'UTF-8');
  771.  
  772.                     $xml .= '>' $multivalue '</field>';
  773.                 }
  774.             }
  775.             else
  776.             {
  777.                 $xml .= '<field name="' $key '"';
  778.  
  779.                 if ($fieldBoost !== false)
  780.                 {
  781.                     $xml .= ' boost="' $fieldBoost '"';
  782.                 }
  783.  
  784.                 $value htmlspecialchars($valueENT_NOQUOTES'UTF-8');
  785.  
  786.                 $xml .= '>' $value '</field>';
  787.             }
  788.         }
  789.  
  790.         $xml .= '</doc>';
  791.  
  792.         // replace any control characters to avoid Solr XML parser exception
  793.         return $this->_stripCtrlChars($xml);
  794.     }
  795.  
  796.     /**
  797.      * Replace control (non-printable) characters from string that are invalid to Solr's XML parser with a space.
  798.      *
  799.      * @param string $string 
  800.      * @return string 
  801.      */
  802.     protected function _stripCtrlChars($string)
  803.     {
  804.         // See:  http://w3.org/International/questions/qa-forms-utf-8.html
  805.         // Printable utf-8 does not include any of these chars below x7F
  806.         return preg_replace('@[\x00-\x08\x0B\x0C\x0E-\x1F]@'' '$string);
  807.     }
  808.  
  809.     /**
  810.      * Send a commit command.  Will be synchronous unless both wait parameters are set to false.
  811.      *
  812.      * @param boolean $expungeDeletes Defaults to false, merge segments with deletes away
  813.      * @param boolean $waitFlush Defaults to true,  block until index changes are flushed to disk
  814.      * @param boolean $waitSearcher Defaults to true, block until a new searcher is opened and registered as the main query searcher, making the changes visible
  815.      * @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
  816.      * @return Apache_Solr_Response 
  817.      *
  818.      * @throws Apache_Solr_HttpTransportException If an error occurs during the service call
  819.      */
  820.     public function commit($expungeDeletes false$waitFlush true$waitSearcher true$timeout 3600)
  821.     {
  822.         $expungeValue $expungeDeletes 'true' 'false';
  823.         $flushValue $waitFlush 'true' 'false';
  824.         $searcherValue $waitSearcher 'true' 'false';
  825.  
  826.         $rawPost '<commit expungeDeletes="' $expungeValue '" waitFlush="' $flushValue '" waitSearcher="' $searcherValue '" />';
  827.  
  828.         return $this->_sendRawPost($this->_updateUrl$rawPost$timeout);
  829.     }
  830.  
  831.     /**
  832.      * Raw Delete Method. Takes a raw post body and sends it to the update service. Body should be
  833.      * a complete and well formed "delete" xml document
  834.      *
  835.      * @param string $rawPost Expected to be utf-8 encoded xml document
  836.      * @param float $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception)
  837.      * @return Apache_Solr_Response 
  838.      *
  839.      * @throws Apache_Solr_HttpTransportException If an error occurs during the service call
  840.      */
  841.     public function delete($rawPost$timeout 3600)
  842.     {
  843.         return $this->_sendRawPost($this->_updateUrl$rawPost$timeout);
  844.     }
  845.  
  846.     /**
  847.      * Create a delete document based on document ID
  848.      *
  849.      * @param string $id Expected to be utf-8 encoded
  850.      * @param boolean $fromPending 
  851.      * @param boolean $fromCommitted 
  852.      * @param float $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception)
  853.      * @return Apache_Solr_Response 
  854.      *
  855.      * @throws Apache_Solr_HttpTransportException If an error occurs during the service call
  856.      */
  857.     public function deleteById($id$fromPending true$fromCommitted true$timeout 3600)
  858.     {
  859.         $pendingValue $fromPending 'true' 'false';
  860.         $committedValue $fromCommitted 'true' 'false';
  861.  
  862.         //escape special xml characters
  863.         $id htmlspecialchars($idENT_NOQUOTES'UTF-8');
  864.  
  865.         $rawPost '<delete fromPending="' $pendingValue '" fromCommitted="' $committedValue '"><id>' $id '</id></delete>';
  866.  
  867.         return $this->delete($rawPost$timeout);
  868.     }
  869.  
  870.     /**
  871.      * Create and post a delete document based on multiple document IDs.
  872.      *
  873.      * @param array $ids Expected to be utf-8 encoded strings
  874.      * @param boolean $fromPending 
  875.      * @param boolean $fromCommitted 
  876.      * @param float $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception)
  877.      * @return Apache_Solr_Response 
  878.      *
  879.      * @throws Apache_Solr_HttpTransportException If an error occurs during the service call
  880.      */
  881.     public function deleteByMultipleIds($ids$fromPending true$fromCommitted true$timeout 3600)
  882.     {
  883.         $pendingValue $fromPending 'true' 'false';
  884.         $committedValue $fromCommitted 'true' 'false';
  885.  
  886.         $rawPost '<delete fromPending="' $pendingValue '" fromCommitted="' $committedValue '">';
  887.  
  888.         foreach ($ids as $id)
  889.         {
  890.             //escape special xml characters
  891.             $id htmlspecialchars($idENT_NOQUOTES'UTF-8');
  892.  
  893.             $rawPost .= '<id>' $id '</id>';
  894.         }
  895.  
  896.         $rawPost .= '</delete>';
  897.  
  898.         return $this->delete($rawPost$timeout);
  899.     }
  900.  
  901.     /**
  902.      * Create a delete document based on a query and submit it
  903.      *
  904.      * @param string $rawQuery Expected to be utf-8 encoded
  905.      * @param boolean $fromPending 
  906.      * @param boolean $fromCommitted 
  907.      * @param float $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception)
  908.      * @return Apache_Solr_Response 
  909.      *
  910.      * @throws Apache_Solr_HttpTransportException If an error occurs during the service call
  911.      */
  912.     public function deleteByQuery($rawQuery$fromPending true$fromCommitted true$timeout 3600)
  913.     {
  914.         $pendingValue $fromPending 'true' 'false';
  915.         $committedValue $fromCommitted 'true' 'false';
  916.  
  917.         // escape special xml characters
  918.         $rawQuery htmlspecialchars($rawQueryENT_NOQUOTES'UTF-8');
  919.  
  920.         $rawPost '<delete fromPending="' $pendingValue '" fromCommitted="' $committedValue '"><query>' $rawQuery '</query></delete>';
  921.  
  922.         return $this->delete($rawPost$timeout);
  923.     }
  924.  
  925.     /**
  926.      * Use Solr Cell to extract document contents. See {@link http://wiki.apache.org/solr/ExtractingRequestHandler} for information on how
  927.      * to use Solr Cell and what parameters are available.
  928.      *
  929.      * NOTE: when passing an Apache_Solr_Document instance, field names and boosts will automatically be prepended by "literal." and "boost."
  930.      * as appropriate. Any keys from the $params array will NOT be treated this way. Any mappings from the document will overwrite key / value
  931.      * pairs in the params array if they have the same name (e.g. you pass a "literal.id" key and value in your $params array but you also
  932.      * pass in a document isntance with an "id" field" - the document's value(s) will take precedence).
  933.      *
  934.      * @param string $file Path to file to extract data from
  935.      * @param array $params optional array of key value pairs that will be sent with the post (see Solr Cell documentation)
  936.      * @param Apache_Solr_Document $document optional document that will be used to generate post parameters (literal.* and boost.* params)
  937.      * @param string $mimetype optional mimetype specification (for the file being extracted)
  938.      *
  939.      * @return Apache_Solr_Response 
  940.      *
  941.      * @throws Apache_Solr_InvalidArgumentException if $file, $params, or $document are invalid.
  942.      */
  943.     public function extract($file$params array()$document null$mimetype 'application/octet-stream')
  944.     {
  945.         // check if $params is an array (allow null for default empty array)
  946.         if (!is_null($params))
  947.         {
  948.             if (!is_array($params))
  949.             {
  950.                 throw new Apache_Solr_InvalidArgumentException("\$params must be a valid array or null");
  951.             }
  952.         }
  953.         else
  954.         {
  955.             $params array();
  956.         }
  957.         
  958.         // if $file is an http request, defer to extractFromUrl instead
  959.         if (substr($file07== 'http://' || substr($file08== 'https://')
  960.         {
  961.             return $this->extractFromUrl($file$params$document$mimetype);
  962.         }
  963.         
  964.         // read the contents of the file
  965.         $contents @file_get_contents($file);
  966.  
  967.         if ($contents !== false)
  968.         {
  969.             // add the resource.name parameter if not specified
  970.             if (!isset($params['resource.name']))
  971.             {
  972.                 $params['resource.name'basename($file);
  973.             }
  974.  
  975.             // delegate the rest to extractFromString
  976.             return $this->extractFromString($contents$params$document$mimetype);
  977.         }
  978.         else
  979.         {
  980.             throw new Apache_Solr_InvalidArgumentException("File '{$file}' is empty or could not be read");
  981.         }
  982.     }
  983.     
  984.     /**
  985.      * Use Solr Cell to extract document contents. See {@link http://wiki.apache.org/solr/ExtractingRequestHandler} for information on how
  986.      * to use Solr Cell and what parameters are available.
  987.      *
  988.      * NOTE: when passing an Apache_Solr_Document instance, field names and boosts will automatically be prepended by "literal." and "boost."
  989.      * as appropriate. Any keys from the $params array will NOT be treated this way. Any mappings from the document will overwrite key / value
  990.      * pairs in the params array if they have the same name (e.g. you pass a "literal.id" key and value in your $params array but you also
  991.      * pass in a document isntance with an "id" field" - the document's value(s) will take precedence).
  992.      *
  993.      * @param string $data Data that will be passed to Solr Cell
  994.      * @param array $params optional array of key value pairs that will be sent with the post (see Solr Cell documentation)
  995.      * @param Apache_Solr_Document $document optional document that will be used to generate post parameters (literal.* and boost.* params)
  996.      * @param string $mimetype optional mimetype specification (for the file being extracted)
  997.      *
  998.      * @return Apache_Solr_Response 
  999.      *
  1000.      * @throws Apache_Solr_InvalidArgumentException if $file, $params, or $document are invalid.
  1001.      *
  1002.      * @todo Should be using multipart/form-data to post parameter values, but I could not get my implementation to work. Needs revisisted.
  1003.      */
  1004.     public function extractFromString($data$params array()$document null$mimetype 'application/octet-stream')
  1005.     {
  1006.         // check if $params is an array (allow null for default empty array)
  1007.         if (!is_null($params))
  1008.         {
  1009.             if (!is_array($params))
  1010.             {
  1011.                 throw new Apache_Solr_InvalidArgumentException("\$params must be a valid array or null");
  1012.             }
  1013.         }
  1014.         else
  1015.         {
  1016.             $params array();
  1017.         }
  1018.  
  1019.         // make sure we receive our response in JSON and have proper name list treatment
  1020.         $params['wt'self::SOLR_WRITER;
  1021.         $params['json.nl'$this->_namedListTreatment;
  1022.  
  1023.         // check if $document is an Apache_Solr_Document instance
  1024.         if (!is_null($document&& $document instanceof Apache_Solr_Document)
  1025.         {
  1026.             // iterate document, adding literal.* and boost.* fields to $params as appropriate
  1027.             foreach ($document as $field => $fieldValue)
  1028.             {
  1029.                 // check if we need to add a boost.* parameters
  1030.                 $fieldBoost $document->getFieldBoost($field);
  1031.  
  1032.                 if ($fieldBoost !== false)
  1033.                 {
  1034.                     $params["boost.{$field}"$fieldBoost;
  1035.                 }
  1036.  
  1037.                 // add the literal.* parameter
  1038.                 $params["literal.{$field}"$fieldValue;
  1039.             }
  1040.         }
  1041.  
  1042.         // params will be sent to SOLR in the QUERY STRING
  1043.         $queryString $this->_generateQueryString($params);
  1044.  
  1045.         // the file contents will be sent to SOLR as the POST BODY - we use application/octect-stream as default mimetype
  1046.         return $this->_sendRawPost($this->_extractUrl $this->_queryDelimiter . $queryString$datafalse$mimetype);
  1047.     }
  1048.     
  1049.     /**
  1050.      * Use Solr Cell to extract document contents. See {@link http://wiki.apache.org/solr/ExtractingRequestHandler} for information on how
  1051.      * to use Solr Cell and what parameters are available.
  1052.      *
  1053.      * NOTE: when passing an Apache_Solr_Document instance, field names and boosts will automatically be prepended by "literal." and "boost."
  1054.      * as appropriate. Any keys from the $params array will NOT be treated this way. Any mappings from the document will overwrite key / value
  1055.      * pairs in the params array if they have the same name (e.g. you pass a "literal.id" key and value in your $params array but you also
  1056.      * pass in a document isntance with an "id" field" - the document's value(s) will take precedence).
  1057.      *
  1058.      * @param string $url URL
  1059.      * @param array $params optional array of key value pairs that will be sent with the post (see Solr Cell documentation)
  1060.      * @param Apache_Solr_Document $document optional document that will be used to generate post parameters (literal.* and boost.* params)
  1061.      * @param string $mimetype optional mimetype specification (for the file being extracted)
  1062.      *
  1063.      * @return Apache_Solr_Response 
  1064.      *
  1065.      * @throws Apache_Solr_InvalidArgumentException if $url, $params, or $document are invalid.
  1066.      */
  1067.     public function extractFromUrl($url$params array()$document null$mimetype 'application/octet-stream')
  1068.     {
  1069.         // check if $params is an array (allow null for default empty array)
  1070.         if (!is_null($params))
  1071.         {
  1072.             if (!is_array($params))
  1073.             {
  1074.                 throw new Apache_Solr_InvalidArgumentException("\$params must be a valid array or null");
  1075.             }
  1076.         }
  1077.         else
  1078.         {
  1079.             $params array();
  1080.         }
  1081.  
  1082.         $httpTransport $this->getHttpTransport();
  1083.         
  1084.         // read the contents of the URL using our configured Http Transport and default timeout
  1085.         $httpResponse $httpTransport->performGetRequest($url);
  1086.         
  1087.         // check that its a 200 response
  1088.         if ($httpResponse->getStatusCode(== 200)
  1089.         {
  1090.             // add the resource.name parameter if not specified
  1091.             if (!isset($params['resource.name']))
  1092.             {
  1093.                 $params['resource.name'$url;
  1094.             }
  1095.  
  1096.             // delegate the rest to extractFromString
  1097.             return $this->extractFromString($httpResponse->getBody()$params$document$mimetype);
  1098.         }
  1099.         else
  1100.         {
  1101.             throw new Apache_Solr_InvalidArgumentException("URL '{$url}' returned non 200 response code");
  1102.         }
  1103.     }
  1104.  
  1105.     /**
  1106.      * Send an optimize command.  Will be synchronous unless both wait parameters are set
  1107.      * to false.
  1108.      *
  1109.      * @param boolean $waitFlush 
  1110.      * @param boolean $waitSearcher 
  1111.      * @param float $timeout Maximum expected duration of the commit operation on the server (otherwise, will throw a communication exception)
  1112.      * @return Apache_Solr_Response 
  1113.      *
  1114.      * @throws Apache_Solr_HttpTransportException If an error occurs during the service call
  1115.      */
  1116.     public function optimize($waitFlush true$waitSearcher true$timeout 3600)
  1117.     {
  1118.         $flushValue $waitFlush 'true' 'false';
  1119.         $searcherValue $waitSearcher 'true' 'false';
  1120.  
  1121.         $rawPost '<optimize waitFlush="' $flushValue '" waitSearcher="' $searcherValue '" />';
  1122.  
  1123.         return $this->_sendRawPost($this->_updateUrl$rawPost$timeout);
  1124.     }
  1125.  
  1126.     /**
  1127.      * Simple Search interface
  1128.      *
  1129.      * @param string $query The raw query string
  1130.      * @param int $offset The starting offset for result documents
  1131.      * @param int $limit The maximum number of result documents to return
  1132.      * @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)
  1133.      * @param string $method The HTTP method (Apache_Solr_Service::METHOD_GET or Apache_Solr_Service::METHOD::POST)
  1134.      * @return Apache_Solr_Response 
  1135.      *
  1136.      * @throws Apache_Solr_HttpTransportException If an error occurs during the service call
  1137.      * @throws Apache_Solr_InvalidArgumentException If an invalid HTTP method is used
  1138.      */
  1139.     public function search($query$offset 0$limit 10$params array()$method self::METHOD_GET)
  1140.     {
  1141.         // ensure params is an array
  1142.         if (!is_null($params))
  1143.         {
  1144.             if (!is_array($params))
  1145.             {
  1146.                 // params was specified but was not an array - invalid
  1147.                 throw new Apache_Solr_InvalidArgumentException("\$params must be a valid array or null");
  1148.             }
  1149.         }
  1150.         else
  1151.         {
  1152.             $params array();
  1153.         }
  1154.         
  1155.         // construct our full parameters
  1156.  
  1157.         // common parameters in this interface
  1158.         $params['wt'self::SOLR_WRITER;
  1159.         $params['json.nl'$this->_namedListTreatment;
  1160.  
  1161.         $params['q'$query;
  1162.         $params['start'$offset;
  1163.         $params['rows'$limit;
  1164.  
  1165.         $queryString $this->_generateQueryString($params);
  1166.  
  1167.         if ($method == self::METHOD_GET)
  1168.         {
  1169.             return $this->_sendRawGet($this->_searchUrl . $this->_queryDelimiter . $queryString);
  1170.         }
  1171.         else if ($method == self::METHOD_POST)
  1172.         {
  1173.             return $this->_sendRawPost($this->_searchUrl$queryStringFALSE'application/x-www-form-urlencoded; charset=UTF-8');
  1174.         }
  1175.         else
  1176.         {
  1177.             throw new Apache_Solr_InvalidArgumentException("Unsupported method '$method', please use the Apache_Solr_Service::METHOD_* constants");
  1178.         }
  1179.     }
  1180. }

Documentation generated on Wed, 04 May 2011 11:01:19 -0400 by phpDocumentor 1.4.3