vendor/ruflin/elastica/lib/Elastica/Client.php line 667

Open in your IDE?
  1. <?php
  2. namespace Elastica;
  3. use Elastica\Bulk\Action;
  4. use Elastica\Exception\ConnectionException;
  5. use Elastica\Exception\InvalidException;
  6. use Elastica\Script\AbstractScript;
  7. use Elasticsearch\Endpoints\AbstractEndpoint;
  8. use Elasticsearch\Endpoints\Indices\ForceMerge;
  9. use Elasticsearch\Endpoints\Indices\Refresh;
  10. use Elasticsearch\Endpoints\Update;
  11. use Psr\Log\LoggerInterface;
  12. use Psr\Log\NullLogger;
  13. /**
  14.  * Client to connect the the elasticsearch server.
  15.  *
  16.  * @author Nicolas Ruflin <spam@ruflin.com>
  17.  */
  18. class Client
  19. {
  20.     /**
  21.      * Config with defaults.
  22.      *
  23.      * log: Set to true, to enable logging, set a string to log to a specific file
  24.      * retryOnConflict: Use in \Elastica\Client::updateDocument
  25.      * bigintConversion: Set to true to enable the JSON bigint to string conversion option (see issue #717)
  26.      *
  27.      * @var array
  28.      */
  29.     protected $_config = [
  30.         'host' => null,
  31.         'port' => null,
  32.         'path' => null,
  33.         'url' => null,
  34.         'proxy' => null,
  35.         'transport' => null,
  36.         'persistent' => true,
  37.         'timeout' => null,
  38.         'connections' => [], // host, port, path, timeout, transport, compression, persistent, timeout, config -> (curl, headers, url)
  39.         'roundRobin' => false,
  40.         'log' => false,
  41.         'retryOnConflict' => 0,
  42.         'bigintConversion' => false,
  43.         'username' => null,
  44.         'password' => null,
  45.     ];
  46.     /**
  47.      * @var callback
  48.      */
  49.     protected $_callback;
  50.     /**
  51.      * @var Connection\ConnectionPool
  52.      */
  53.     protected $_connectionPool;
  54.     /**
  55.      * @var \Elastica\Request|null
  56.      */
  57.     protected $_lastRequest;
  58.     /**
  59.      * @var \Elastica\Response|null
  60.      */
  61.     protected $_lastResponse;
  62.     /**
  63.      * @var LoggerInterface
  64.      */
  65.     protected $_logger;
  66.     /**
  67.      * @var string
  68.      */
  69.     protected $_version;
  70.     /**
  71.      * Creates a new Elastica client.
  72.      *
  73.      * @param array           $config   OPTIONAL Additional config options
  74.      * @param callback        $callback OPTIONAL Callback function which can be used to be notified about errors (for example connection down)
  75.      * @param LoggerInterface $logger
  76.      */
  77.     public function __construct(array $config = [], $callback nullLoggerInterface $logger null)
  78.     {
  79.         $this->_callback $callback;
  80.         if (!$logger && isset($config['log']) && $config['log']) {
  81.             $logger = new Log($config['log']);
  82.         }
  83.         $this->_logger $logger ?: new NullLogger();
  84.         $this->setConfig($config);
  85.         $this->_initConnections();
  86.     }
  87.     /**
  88.      * Get current version.
  89.      *
  90.      * @return string
  91.      */
  92.     public function getVersion()
  93.     {
  94.         if ($this->_version) {
  95.             return $this->_version;
  96.         }
  97.         $data $this->request('/')->getData();
  98.         return $this->_version $data['version']['number'];
  99.     }
  100.     /**
  101.      * Inits the client connections.
  102.      */
  103.     protected function _initConnections()
  104.     {
  105.         $connections = [];
  106.         foreach ($this->getConfig('connections') as $connection) {
  107.             $connections[] = Connection::create($this->_prepareConnectionParams($connection));
  108.         }
  109.         if (isset($this->_config['servers'])) {
  110.             foreach ($this->getConfig('servers') as $server) {
  111.                 $connections[] = Connection::create($this->_prepareConnectionParams($server));
  112.             }
  113.         }
  114.         // If no connections set, create default connection
  115.         if (empty($connections)) {
  116.             $connections[] = Connection::create($this->_prepareConnectionParams($this->getConfig()));
  117.         }
  118.         if (!isset($this->_config['connectionStrategy'])) {
  119.             if ($this->getConfig('roundRobin') === true) {
  120.                 $this->setConfigValue('connectionStrategy''RoundRobin');
  121.             } else {
  122.                 $this->setConfigValue('connectionStrategy''Simple');
  123.             }
  124.         }
  125.         $strategy Connection\Strategy\StrategyFactory::create($this->getConfig('connectionStrategy'));
  126.         $this->_connectionPool = new Connection\ConnectionPool($connections$strategy$this->_callback);
  127.     }
  128.     /**
  129.      * Creates a Connection params array from a Client or server config array.
  130.      *
  131.      * @param array $config
  132.      *
  133.      * @return array
  134.      */
  135.     protected function _prepareConnectionParams(array $config)
  136.     {
  137.         $params = [];
  138.         $params['config'] = [];
  139.         foreach ($config as $key => $value) {
  140.             if (in_array($key, ['bigintConversion''curl''headers''url'])) {
  141.                 $params['config'][$key] = $value;
  142.             } else {
  143.                 $params[$key] = $value;
  144.             }
  145.         }
  146.         return $params;
  147.     }
  148.     /**
  149.      * Sets specific config values (updates and keeps default values).
  150.      *
  151.      * @param array $config Params
  152.      *
  153.      * @return $this
  154.      */
  155.     public function setConfig(array $config)
  156.     {
  157.         foreach ($config as $key => $value) {
  158.             $this->_config[$key] = $value;
  159.         }
  160.         return $this;
  161.     }
  162.     /**
  163.      * Returns a specific config key or the whole
  164.      * config array if not set.
  165.      *
  166.      * @param string $key Config key
  167.      *
  168.      * @throws \Elastica\Exception\InvalidException
  169.      *
  170.      * @return array|string Config value
  171.      */
  172.     public function getConfig($key '')
  173.     {
  174.         if (empty($key)) {
  175.             return $this->_config;
  176.         }
  177.         if (!array_key_exists($key$this->_config)) {
  178.             throw new InvalidException('Config key is not set: '.$key);
  179.         }
  180.         return $this->_config[$key];
  181.     }
  182.     /**
  183.      * Sets / overwrites a specific config value.
  184.      *
  185.      * @param string $key   Key to set
  186.      * @param mixed  $value Value
  187.      *
  188.      * @return $this
  189.      */
  190.     public function setConfigValue($key$value)
  191.     {
  192.         return $this->setConfig([$key => $value]);
  193.     }
  194.     /**
  195.      * @param array|string $keys    config key or path of config keys
  196.      * @param mixed        $default default value will be returned if key was not found
  197.      *
  198.      * @return mixed
  199.      */
  200.     public function getConfigValue($keys$default null)
  201.     {
  202.         $value $this->_config;
  203.         foreach ((array) $keys as $key) {
  204.             if (isset($value[$key])) {
  205.                 $value $value[$key];
  206.             } else {
  207.                 return $default;
  208.             }
  209.         }
  210.         return $value;
  211.     }
  212.     /**
  213.      * Returns the index for the given connection.
  214.      *
  215.      * @param string $name Index name to create connection to
  216.      *
  217.      * @return \Elastica\Index Index for the given name
  218.      */
  219.     public function getIndex($name)
  220.     {
  221.         return new Index($this$name);
  222.     }
  223.     /**
  224.      * Adds a HTTP Header.
  225.      *
  226.      * @param string $header      The HTTP Header
  227.      * @param string $headerValue The HTTP Header Value
  228.      *
  229.      * @throws \Elastica\Exception\InvalidException If $header or $headerValue is not a string
  230.      *
  231.      * @return $this
  232.      */
  233.     public function addHeader($header$headerValue)
  234.     {
  235.         if (is_string($header) && is_string($headerValue)) {
  236.             $this->_config['headers'][$header] = $headerValue;
  237.         } else {
  238.             throw new InvalidException('Header must be a string');
  239.         }
  240.         return $this;
  241.     }
  242.     /**
  243.      * Remove a HTTP Header.
  244.      *
  245.      * @param string $header The HTTP Header to remove
  246.      *
  247.      * @throws \Elastica\Exception\InvalidException If $header is not a string
  248.      *
  249.      * @return $this
  250.      */
  251.     public function removeHeader($header)
  252.     {
  253.         if (is_string($header)) {
  254.             if (array_key_exists($header$this->_config['headers'])) {
  255.                 unset($this->_config['headers'][$header]);
  256.             }
  257.         } else {
  258.             throw new InvalidException('Header must be a string');
  259.         }
  260.         return $this;
  261.     }
  262.     /**
  263.      * Uses _bulk to send documents to the server.
  264.      *
  265.      * Array of \Elastica\Document as input. Index and type has to be
  266.      * set inside the document, because for bulk settings documents,
  267.      * documents can belong to any type and index
  268.      *
  269.      * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
  270.      *
  271.      * @param array|\Elastica\Document[] $docs Array of Elastica\Document
  272.      *
  273.      * @throws \Elastica\Exception\InvalidException If docs is empty
  274.      *
  275.      * @return \Elastica\Bulk\ResponseSet Response object
  276.      */
  277.     public function updateDocuments(array $docs)
  278.     {
  279.         if (empty($docs)) {
  280.             throw new InvalidException('Array has to consist of at least one element');
  281.         }
  282.         $bulk = new Bulk($this);
  283.         $bulk->addDocuments($docsAction::OP_TYPE_UPDATE);
  284.         return $bulk->send();
  285.     }
  286.     /**
  287.      * Uses _bulk to send documents to the server.
  288.      *
  289.      * Array of \Elastica\Document as input. Index and type has to be
  290.      * set inside the document, because for bulk settings documents,
  291.      * documents can belong to any type and index
  292.      *
  293.      * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
  294.      *
  295.      * @param array|\Elastica\Document[] $docs Array of Elastica\Document
  296.      *
  297.      * @throws \Elastica\Exception\InvalidException If docs is empty
  298.      *
  299.      * @return \Elastica\Bulk\ResponseSet Response object
  300.      */
  301.     public function addDocuments(array $docs)
  302.     {
  303.         if (empty($docs)) {
  304.             throw new InvalidException('Array has to consist of at least one element');
  305.         }
  306.         $bulk = new Bulk($this);
  307.         $bulk->addDocuments($docs);
  308.         return $bulk->send();
  309.     }
  310.     /**
  311.      * Update document, using update script. Requires elasticsearch >= 0.19.0.
  312.      *
  313.      * @param int|string                                               $id      document id
  314.      * @param array|\Elastica\Script\AbstractScript|\Elastica\Document $data    raw data for request body
  315.      * @param string                                                   $index   index to update
  316.      * @param string                                                   $type    type of index to update
  317.      * @param array                                                    $options array of query params to use for query. For possible options check es api
  318.      *
  319.      * @return \Elastica\Response
  320.      *
  321.      * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-update.html
  322.      */
  323.     public function updateDocument($id$data$index$type, array $options = [])
  324.     {
  325.         $endpoint = new Update();
  326.         $endpoint->setID($id);
  327.         $endpoint->setIndex($index);
  328.         $endpoint->setType($type);
  329.         if ($data instanceof AbstractScript) {
  330.             $requestData $data->toArray();
  331.         } elseif ($data instanceof Document) {
  332.             $requestData = ['doc' => $data->getData()];
  333.             if ($data->getDocAsUpsert()) {
  334.                 $requestData['doc_as_upsert'] = true;
  335.             }
  336.             $docOptions $data->getOptions(
  337.                 [
  338.                     'version',
  339.                     'version_type',
  340.                     'routing',
  341.                     'percolate',
  342.                     'parent',
  343.                     'fields',
  344.                     'retry_on_conflict',
  345.                     'consistency',
  346.                     'replication',
  347.                     'refresh',
  348.                     'timeout',
  349.                 ]
  350.             );
  351.             $options += $docOptions;
  352.             // set fields param to source only if options was not set before
  353.             if ($data instanceof Document && ($data->isAutoPopulate()
  354.                 || $this->getConfigValue(['document''autoPopulate'], false))
  355.                 && !isset($options['fields'])
  356.             ) {
  357.                 $options['fields'] = '_source';
  358.             }
  359.         } else {
  360.             $requestData $data;
  361.         }
  362.         //If an upsert document exists
  363.         if ($data instanceof AbstractScript || $data instanceof Document) {
  364.             if ($data->hasUpsert()) {
  365.                 $requestData['upsert'] = $data->getUpsert()->getData();
  366.             }
  367.         }
  368.         if (!isset($options['retry_on_conflict'])) {
  369.             if ($retryOnConflict $this->getConfig('retryOnConflict')) {
  370.                 $options['retry_on_conflict'] = $retryOnConflict;
  371.             }
  372.         }
  373.         $endpoint->setBody($requestData);
  374.         $endpoint->setParams($options);
  375.         $response $this->requestEndpoint($endpoint);
  376.         if ($response->isOk()
  377.             && $data instanceof Document
  378.             && ($data->isAutoPopulate() || $this->getConfigValue(['document''autoPopulate'], false))
  379.         ) {
  380.             $responseData $response->getData();
  381.             if (isset($responseData['_version'])) {
  382.                 $data->setVersion($responseData['_version']);
  383.             }
  384.             if (isset($options['fields'])) {
  385.                 $this->_populateDocumentFieldsFromResponse($response$data$options['fields']);
  386.             }
  387.         }
  388.         return $response;
  389.     }
  390.     /**
  391.      * @param \Elastica\Response $response
  392.      * @param \Elastica\Document $document
  393.      * @param string             $fields   Array of field names to be populated or '_source' if whole document data should be updated
  394.      */
  395.     protected function _populateDocumentFieldsFromResponse(Response $responseDocument $document$fields)
  396.     {
  397.         $responseData $response->getData();
  398.         if ('_source' == $fields) {
  399.             if (isset($responseData['get']['_source']) && is_array($responseData['get']['_source'])) {
  400.                 $document->setData($responseData['get']['_source']);
  401.             }
  402.         } else {
  403.             $keys explode(','$fields);
  404.             $data $document->getData();
  405.             foreach ($keys as $key) {
  406.                 if (isset($responseData['get']['fields'][$key])) {
  407.                     $data[$key] = $responseData['get']['fields'][$key];
  408.                 } elseif (isset($data[$key])) {
  409.                     unset($data[$key]);
  410.                 }
  411.             }
  412.             $document->setData($data);
  413.         }
  414.     }
  415.     /**
  416.      * Bulk deletes documents.
  417.      *
  418.      * @param array|\Elastica\Document[] $docs
  419.      *
  420.      * @throws \Elastica\Exception\InvalidException
  421.      *
  422.      * @return \Elastica\Bulk\ResponseSet
  423.      */
  424.     public function deleteDocuments(array $docs)
  425.     {
  426.         if (empty($docs)) {
  427.             throw new InvalidException('Array has to consist of at least one element');
  428.         }
  429.         $bulk = new Bulk($this);
  430.         $bulk->addDocuments($docsAction::OP_TYPE_DELETE);
  431.         return $bulk->send();
  432.     }
  433.     /**
  434.      * Returns the status object for all indices.
  435.      *
  436.      * @return \Elastica\Status Status object
  437.      */
  438.     public function getStatus()
  439.     {
  440.         return new Status($this);
  441.     }
  442.     /**
  443.      * Returns the current cluster.
  444.      *
  445.      * @return \Elastica\Cluster Cluster object
  446.      */
  447.     public function getCluster()
  448.     {
  449.         return new Cluster($this);
  450.     }
  451.     /**
  452.      * Establishes the client connections.
  453.      */
  454.     public function connect()
  455.     {
  456.         return $this->_initConnections();
  457.     }
  458.     /**
  459.      * @param \Elastica\Connection $connection
  460.      *
  461.      * @return $this
  462.      */
  463.     public function addConnection(Connection $connection)
  464.     {
  465.         $this->_connectionPool->addConnection($connection);
  466.         return $this;
  467.     }
  468.     /**
  469.      * Determines whether a valid connection is available for use.
  470.      *
  471.      * @return bool
  472.      */
  473.     public function hasConnection()
  474.     {
  475.         return $this->_connectionPool->hasConnection();
  476.     }
  477.     /**
  478.      * @throws \Elastica\Exception\ClientException
  479.      *
  480.      * @return \Elastica\Connection
  481.      */
  482.     public function getConnection()
  483.     {
  484.         return $this->_connectionPool->getConnection();
  485.     }
  486.     /**
  487.      * @return \Elastica\Connection[]
  488.      */
  489.     public function getConnections()
  490.     {
  491.         return $this->_connectionPool->getConnections();
  492.     }
  493.     /**
  494.      * @return \Elastica\Connection\Strategy\StrategyInterface
  495.      */
  496.     public function getConnectionStrategy()
  497.     {
  498.         return $this->_connectionPool->getStrategy();
  499.     }
  500.     /**
  501.      * @param array|\Elastica\Connection[] $connections
  502.      *
  503.      * @return $this
  504.      */
  505.     public function setConnections(array $connections)
  506.     {
  507.         $this->_connectionPool->setConnections($connections);
  508.         return $this;
  509.     }
  510.     /**
  511.      * Deletes documents with the given ids, index, type from the index.
  512.      *
  513.      * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
  514.      *
  515.      * @param array                  $ids     Document ids
  516.      * @param string|\Elastica\Index $index   Index name
  517.      * @param string|\Elastica\Type  $type    Type of documents
  518.      * @param string|bool            $routing Optional routing key for all ids
  519.      *
  520.      * @throws \Elastica\Exception\InvalidException
  521.      *
  522.      * @return \Elastica\Bulk\ResponseSet Response  object
  523.      */
  524.     public function deleteIds(array $ids$index$type$routing false)
  525.     {
  526.         if (empty($ids)) {
  527.             throw new InvalidException('Array has to consist of at least one id');
  528.         }
  529.         $bulk = new Bulk($this);
  530.         $bulk->setIndex($index);
  531.         $bulk->setType($type);
  532.         foreach ($ids as $id) {
  533.             $action = new Action(Action::OP_TYPE_DELETE);
  534.             $action->setId($id);
  535.             if (!empty($routing)) {
  536.                 $action->setRouting($routing);
  537.             }
  538.             $bulk->addAction($action);
  539.         }
  540.         return $bulk->send();
  541.     }
  542.     /**
  543.      * Bulk operation.
  544.      *
  545.      * Every entry in the params array has to exactly on array
  546.      * of the bulk operation. An example param array would be:
  547.      *
  548.      * array(
  549.      *         array('index' => array('_index' => 'test', '_type' => 'user', '_id' => '1')),
  550.      *         array('user' => array('name' => 'hans')),
  551.      *         array('delete' => array('_index' => 'test', '_type' => 'user', '_id' => '2'))
  552.      * );
  553.      *
  554.      * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
  555.      *
  556.      * @param array $params Parameter array
  557.      *
  558.      * @throws \Elastica\Exception\ResponseException
  559.      * @throws \Elastica\Exception\InvalidException
  560.      *
  561.      * @return \Elastica\Bulk\ResponseSet Response object
  562.      */
  563.     public function bulk(array $params)
  564.     {
  565.         if (empty($params)) {
  566.             throw new InvalidException('Array has to consist of at least one param');
  567.         }
  568.         $bulk = new Bulk($this);
  569.         $bulk->addRawData($params);
  570.         return $bulk->send();
  571.     }
  572.     /**
  573.      * Makes calls to the elasticsearch server based on this index.
  574.      *
  575.      * It's possible to make any REST query directly over this method
  576.      *
  577.      * @param string       $path        Path to call
  578.      * @param string       $method      Rest method to use (GET, POST, DELETE, PUT)
  579.      * @param array|string $data        OPTIONAL Arguments as array or pre-encoded string
  580.      * @param array        $query       OPTIONAL Query params
  581.      * @param string       $contentType Content-Type sent with this request
  582.      *
  583.      * @throws Exception\ConnectionException|\Exception
  584.      *
  585.      * @return Response Response object
  586.      */
  587.     public function request($path$method Request::GET$data = [], array $query = [], $contentType Request::DEFAULT_CONTENT_TYPE)
  588.     {
  589.         $connection $this->getConnection();
  590.         $request $this->_lastRequest = new Request($path$method$data$query$connection$contentType);
  591.         $this->_lastResponse null;
  592.         try {
  593.             $response $this->_lastResponse $request->send();
  594.         } catch (ConnectionException $e) {
  595.             $this->_connectionPool->onFail($connection$e$this);
  596.             $this->_log($e);
  597.             // In case there is no valid connection left, throw exception which caused the disabling of the connection.
  598.             if (!$this->hasConnection()) {
  599.                 throw $e;
  600.             }
  601.             return $this->request($path$method$data$query);
  602.         }
  603.         $this->_log($request);
  604.         return $response;
  605.     }
  606.     /**
  607.      * Makes calls to the elasticsearch server with usage official client Endpoint.
  608.      *
  609.      * @param AbstractEndpoint $endpoint
  610.      *
  611.      * @return Response
  612.      */
  613.     public function requestEndpoint(AbstractEndpoint $endpoint)
  614.     {
  615.         return $this->request(
  616.             ltrim($endpoint->getURI(), '/'),
  617.             $endpoint->getMethod(),
  618.             null === $endpoint->getBody() ? [] : $endpoint->getBody(),
  619.             $endpoint->getParams()
  620.         );
  621.     }
  622.     /**
  623.      * logging.
  624.      *
  625.      * @deprecated Overwriting Client->_log is deprecated. Handle logging functionality by using a custom LoggerInterface.
  626.      *
  627.      * @param mixed $context
  628.      */
  629.     protected function _log($context)
  630.     {
  631.         if ($context instanceof ConnectionException) {
  632.             $this->_logger->error('Elastica Request Failure', [
  633.                 'exception' => $context,
  634.                 'request' => $context->getRequest()->toArray(),
  635.                 'retry' => $this->hasConnection(),
  636.             ]);
  637.             return;
  638.         }
  639.         if ($context instanceof Request) {
  640.             $this->_logger->debug('Elastica Request', [
  641.                 'request' => $context->toArray(),
  642.                 'response' => $this->_lastResponse $this->_lastResponse->getData() : null,
  643.                 'responseStatus' => $this->_lastResponse $this->_lastResponse->getStatus() : null,
  644.             ]);
  645.             return;
  646.         }
  647.         $this->_logger->debug('Elastica Request', [
  648.             'message' => $context,
  649.         ]);
  650.     }
  651.     /**
  652.      * Optimizes all search indices.
  653.      *
  654.      * @param array $args OPTIONAL Optional arguments
  655.      *
  656.      * @return \Elastica\Response Response object
  657.      *
  658.      * @deprecated Replaced by forcemergeAll
  659.      * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-optimize.html
  660.      */
  661.     public function optimizeAll($args = [])
  662.     {
  663.         trigger_error('Deprecated: Elastica\Client::optimizeAll() is deprecated and will be removed in further Elastica releases. Use Elastica\Client::forcemergeAll() instead.'E_USER_DEPRECATED);
  664.         return $this->forcemergeAll($args);
  665.     }
  666.     /**
  667.      * Force merges all search indices.
  668.      *
  669.      * @param array $args OPTIONAL Optional arguments
  670.      *
  671.      * @return \Elastica\Response Response object
  672.      *
  673.      * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-forcemerge.html
  674.      */
  675.     public function forcemergeAll($args = [])
  676.     {
  677.         $endpoint = new ForceMerge();
  678.         $endpoint->setParams($args);
  679.         return $this->requestEndpoint($endpoint);
  680.     }
  681.     /**
  682.      * Refreshes all search indices.
  683.      *
  684.      * @return \Elastica\Response Response object
  685.      *
  686.      * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-refresh.html
  687.      */
  688.     public function refreshAll()
  689.     {
  690.         return $this->requestEndpoint(new Refresh());
  691.     }
  692.     /**
  693.      * @return Request|null
  694.      */
  695.     public function getLastRequest()
  696.     {
  697.         return $this->_lastRequest;
  698.     }
  699.     /**
  700.      * @return Response|null
  701.      */
  702.     public function getLastResponse()
  703.     {
  704.         return $this->_lastResponse;
  705.     }
  706.     /**
  707.      * Replace the existing logger.
  708.      *
  709.      * @param LoggerInterface $logger
  710.      *
  711.      * @return $this
  712.      */
  713.     public function setLogger(LoggerInterface $logger)
  714.     {
  715.         $this->_logger $logger;
  716.         return $this;
  717.     }
  718. }