Skip to content

Commit

Permalink
phpDocumentor#636: Added EngineManager and refactored code
Browse files Browse the repository at this point in the history
In this commit I cleaned up the code by adding DocBlocks and renaming
the Engine namespace to Adapter in order to be more explicit in our
intention with that code.

In order to provide a clear entry point and extension point I added an
EngineManager class, inspired on Doctrine's EntityManager, that calls
the correct adapter and works as a frontend.
  • Loading branch information
mvriel committed Feb 25, 2014
1 parent ce446ea commit 2b26c21
Show file tree
Hide file tree
Showing 14 changed files with 416 additions and 72 deletions.
57 changes: 57 additions & 0 deletions src/phpDocumentor/Plugin/Search/Adapter/AdapterInterface.php
@@ -0,0 +1,57 @@
<?php
namespace phpDocumentor\Plugin\Search\Adapter;

use phpDocumentor\Plugin\Search\Document;

interface AdapterInterface
{
/**
* Returns the adapter-specific configuration object.
*
* @return object
*/
public function getConfiguration();

/**
* Evaluates the given expression and tries to find, and return, a number of Documents equal to the amount found or
* the limit if provided.
*
* @param string $expression A query expression used to limit the type of documents returned.
* @param int $start At which point in the result set to start returning documents.
* @param int $limit How many documents to return at maximum.
*
* @return Document[]
*/
public function find($expression, $start = 0, $limit = 10);

/**
* Marks the given document for addition in the Search Engine so it can be found later again.
*
* Please note that the actual writing to the Search Engine happens once the {@see flush()} method is called. Until
* then all addition and removal operations are stored in memory and unless flushed not found in the Search Engine.
*
* @param Document $document
*
* @return void
*/
public function persist(Document $document);

/**
* Marks a document for removal so it will be removed once the flush method is called.
*
* Please note that the actual writing to the Search Engine happens once the {@see flush()} method is called. Until
* then all addition and removal operations are stored in memory and unless flushed not found in the Search Engine.
*
* @param Document $document
*
* @return void
*/
public function remove(Document $document);

/**
* Writes all changes to the Search Engine's data to the Search Engine.
*
* @return void
*/
public function flush();
}
@@ -1,5 +1,5 @@
<?php
namespace phpDocumentor\Plugin\Search\Engine\Configuration;
namespace phpDocumentor\Plugin\Search\Adapter\Configuration;

use Guzzle\Http\Client;

Expand Down
@@ -1,5 +1,5 @@
<?php
namespace phpDocumentor\Plugin\Search\Engine\Configuration;
namespace phpDocumentor\Plugin\Search\Adapter\Configuration;

class LunrJs
{
Expand Down
@@ -1,26 +1,49 @@
<?php
namespace phpDocumentor\Plugin\Search\Engine;
namespace phpDocumentor\Plugin\Search\Adapter;

use phpDocumentor\Plugin\Search\Document;

class ElasticSearch implements EngineInterface
class ElasticSearch implements AdapterInterface
{
/** @var Document[] Documents that are ready to be purged from the Search Engine */
protected $removals = array();

/** @var Document[] Documents that are ready to be added or updated in the Search Engine */
protected $updates = array();

/** @var Configuration\ElasticSearch */
/** @var Configuration\ElasticSearch The configuration specific for this Search Engine */
protected $configuration;

/**
* Registers the configuration with this Search Engine.
*
* @param Configuration\ElasticSearch $configuration
*/
public function __construct(Configuration\ElasticSearch $configuration)
{
$this->setConfiguration($configuration);
$this->configuration = $configuration;
}

/**
* {@inheritDoc}
*/
public function getConfiguration()
{
return $this->configuration;
}

/**
* {@inheritDoc}
*/
public function find($expression, $start = 0, $limit = 10)
{
$client = $this->getConfiguration()->getHttpClient();
$result = $client->get($this->getBaseUrl() . '/_search?q=' . $expression);

if (!isset($result->hits->hits)) {
throw new \RuntimeException('An error occurred during the finding of documents');
}

$results = array();
foreach ($result->hits->hits as $hit) {
$document = new Document(json_decode($hit->_source, false));
Expand All @@ -31,11 +54,17 @@ public function find($expression, $start = 0, $limit = 10)
return $results;
}

/**
* {@inheritDoc}
*/
public function persist(Document $document)
{
$this->updates[$document->getId()] = $document;
}

/**
* {@inheritDoc}
*/
public function remove(Document $document)
{
if (isset($this->updates[$document->getId()])) {
Expand All @@ -45,6 +74,9 @@ public function remove(Document $document)
$this->removals[$document->getId()] = $document;
}

/**
* {@inheritDoc}
*/
public function flush()
{
$client = $this->getConfiguration()->getHttpClient();
Expand Down Expand Up @@ -75,6 +107,11 @@ public function flush()
}
}

/**
* Assembles the Base Url (storage path) where the documents are stored in Elastic Search.
*
* @return string
*/
protected function getBaseUrl()
{
return implode(
Expand All @@ -87,24 +124,15 @@ protected function getBaseUrl()
);
}

protected function convert(Document $document)
{
return json_encode($document->getArrayCopy());
}

/**
* @param Configuration\ElasticSearch $configuration
*/
public function setConfiguration(Configuration\ElasticSearch $configuration)
{
$this->configuration = $configuration;
}

/**
* @return \phpDocumentor\Search\Engine\Configuration\ElasticSearch
* Converts the document contents, except id, to a representation that can be sent to ElasticSearch.
*
* @param Document $document
*
* @return string A JSON string containing all fields and their values of a Document.
*/
public function getConfiguration()
protected function convert(Document $document)
{
return $this->configuration;
return json_encode($document->getArrayCopy());
}
}
@@ -1,5 +1,5 @@
<?php
namespace phpDocumentor\Plugin\Search\Engine;
namespace phpDocumentor\Plugin\Search\Adapter;

use phpDocumentor\Plugin\Search\Document;

Expand All @@ -12,47 +12,69 @@
*
* The downside of the latter is that it costs a lot more bandwidth and performance, so for medium-sized
* projects is recommended to install node or use any of the other Search Engines.
* For large projects it is not recommended to use this Search Engine as it will cost too much performance.
* For large projects it is NOT recommended to use this Search Engine as it will cost too much performance.
*
* @link http://lunrjs.com
*/
class LunrJs implements EngineInterface
class LunrJs implements AdapterInterface
{
/** @var Configuration\LunrJs */
protected $configuration;

/** @var Document[] $updates */
protected $updates = array();

/**
* Registers the configuration with this Search Engine.
*
* @param Configuration\LunrJs $configuration
*/
public function __construct(Configuration\LunrJs $configuration)
{
$this->setConfiguration($configuration);
$this->configuration = $configuration;
}

/**
* {@inheritDoc}
*
* @return Configuration\LunrJs
*/
public function getConfiguration()
{
return $this->configuration;
}

/**
* {@inheritDoc}
*
* @todo add support for querying the Lunr.js index using Node or Execjs.
*/
public function find($expression, $start = 0, $limit = 10)
{
throw new \RuntimeException(
'LunrJs is a pure Javascript Full Text Search Engine and can only be invoked from Javascript'
);
}

/**
* {@inheritDoc}
*/
public function persist(Document $document)
{
$this->updates[$document->getId()] = $document;
}

/**
* {@inheritDoc}
*/
public function remove(Document $document)
{
throw new \RuntimeException(
'The LunrJs Search Engine does not support removing documents because the index is rebuilt from scratch'
. ' everytime'
);
// The LunrJs Search Engine does not support removing documents because the index is rebuilt from
// scratch everytime
}

/**
* Writes the stored documents to an index file.
*
* @return void
* {@inheritDoc}
*/
public function flush()
{
Expand All @@ -75,22 +97,16 @@ public function flush()
$index .= $indexName . '.add(' . json_encode($values) . ');';
}

file_put_contents($this->getConfiguration()->getPath() . DIRECTORY_SEPARATOR . 'index.lunr.js', $index);
file_put_contents($this->getIndexPath(), $index);
}

/**
* @param Configuration\LunrJs $configuration
*/
public function setConfiguration(Configuration\LunrJs $configuration)
{
$this->configuration = $configuration;
}

/**
* @return Configuration\LunrJs
* Returns the location of the index file.
*
* @return string
*/
public function getConfiguration()
protected function getIndexPath()
{
return $this->configuration;
return $this->getConfiguration()->getPath() . DIRECTORY_SEPARATOR . 'index.lunr.js';
}
}
@@ -1,5 +1,5 @@
<?php
namespace phpDocumentor\Plugin\Search\Engine;
namespace phpDocumentor\Plugin\Search\Adapter;

class PersistException extends \RuntimeException
{
Expand Down
4 changes: 2 additions & 2 deletions src/phpDocumentor/Plugin/Search/Client/Generator.php
@@ -1,7 +1,7 @@
<?php
namespace phpDocumentor\Search\Client;

use \phpDocumentor\Search\Engine\EngineInterface;
use \phpDocumentor\Plugin\Search\Adapter\AdapterInterface;

class Generator
{
Expand All @@ -13,7 +13,7 @@ public function __construct(\Twig_Environment $twig)
$this->twig = $twig;
}

public function generate(EngineInterface $engine)
public function generate(AdapterInterface $engine)
{
$class_name_parts = explode('\\', get_class($engine));
$engine_type = $class_name_parts[count($class_name_parts)-1];
Expand Down
13 changes: 0 additions & 13 deletions src/phpDocumentor/Plugin/Search/Engine/EngineInterface.php

This file was deleted.

0 comments on commit 2b26c21

Please sign in to comment.