New Api
This commit is contained in:
parent
4c961a757d
commit
15d3f1e4f8
22
Doctrine/AbstractLookup.php
Normal file
22
Doctrine/AbstractLookup.php
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Doctrine;
|
||||
|
||||
use Doctrine\Common\Persistence\ManagerRegistry;
|
||||
use FOS\ElasticaBundle\Type\LookupInterface;
|
||||
|
||||
abstract class AbstractLookup implements LookupInterface
|
||||
{
|
||||
/**
|
||||
* @var \Doctrine\Common\Persistence\ManagerRegistry
|
||||
*/
|
||||
protected $registry;
|
||||
|
||||
/**
|
||||
* @param ManagerRegistry $registry
|
||||
*/
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
$this->registry = $registry;
|
||||
}
|
||||
}
|
49
Doctrine/MongoDB/Lookup.php
Normal file
49
Doctrine/MongoDB/Lookup.php
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Doctrine\MongoDB;
|
||||
|
||||
use FOS\ElasticaBundle\Doctrine\AbstractLookup;
|
||||
use FOS\ElasticaBundle\Type\TypeConfigurationInterface;
|
||||
|
||||
class Lookup extends AbstractLookup
|
||||
{
|
||||
/**
|
||||
* Returns the lookup key.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getKey()
|
||||
{
|
||||
return 'mongodb';
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up objects of a specific type with ids as supplied.
|
||||
*
|
||||
* @param TypeConfigurationInterface $configuration
|
||||
* @param array $ids
|
||||
* @return array
|
||||
*/
|
||||
public function lookup(TypeConfigurationInterface $configuration, array $ids)
|
||||
{
|
||||
$qb = $this->createQueryBuilder($configuration);
|
||||
$qb->hydrate($configuration->isHydrate());
|
||||
|
||||
$qb->field($configuration->getIdentifierProperty())
|
||||
->in($ids);
|
||||
|
||||
return $qb->getQuery()->execute()->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TypeConfigurationInterface $configuration
|
||||
* @return \Doctrine\ODM\MongoDB\Query\Builder
|
||||
*/
|
||||
private function createQueryBuilder(TypeConfigurationInterface $configuration)
|
||||
{
|
||||
$method = $configuration->getRepositoryMethod();
|
||||
$manager = $this->registry->getManagerForClass($configuration->getModelClass());
|
||||
|
||||
return $manager->{$method}($configuration->getModelClass());
|
||||
}
|
||||
}
|
58
Doctrine/ORM/Lookup.php
Normal file
58
Doctrine/ORM/Lookup.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Doctrine\ORM;
|
||||
|
||||
use Doctrine\ORM\Query;
|
||||
use FOS\ElasticaBundle\Doctrine\AbstractLookup;
|
||||
use FOS\ElasticaBundle\Type\TypeConfigurationInterface;
|
||||
|
||||
class Lookup extends AbstractLookup
|
||||
{
|
||||
const ENTITY_ALIAS = 'o';
|
||||
|
||||
/**
|
||||
* Returns the lookup key.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getKey()
|
||||
{
|
||||
return 'orm';
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up objects of a specific type with ids as supplied.
|
||||
*
|
||||
* @param TypeConfigurationInterface $configuration
|
||||
* @param array $ids
|
||||
* @return array
|
||||
*/
|
||||
public function lookup(TypeConfigurationInterface $configuration, array $ids)
|
||||
{
|
||||
$hydrationMode = $configuration->isHydrate() ?
|
||||
Query::HYDRATE_OBJECT :
|
||||
Query::HYDRATE_ARRAY;
|
||||
|
||||
$qb = $this->createQueryBuilder($configuration);
|
||||
|
||||
$qb->andWhere($qb->expr()->in(
|
||||
sprintf('%s.%s', static::ENTITY_ALIAS, $configuration->getIdentifierProperty()),
|
||||
':identifiers'
|
||||
));
|
||||
$qb->setParameter('identifiers', $ids);
|
||||
|
||||
return $qb->getQuery()->execute(array(), $hydrationMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TypeConfigurationInterface $configuration
|
||||
* @return \Doctrine\ORM\QueryBuilder
|
||||
*/
|
||||
private function createQueryBuilder(TypeConfigurationInterface $configuration)
|
||||
{
|
||||
$repository = $this->registry->getRepository($configuration->getModelClass());
|
||||
$method = $configuration->getRepositoryMethod();
|
||||
|
||||
return $repository->{$method}(static::ENTITY_ALIAS);
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ namespace FOS\ElasticaBundle\Elastica;
|
|||
use Elastica\Client as Client;
|
||||
use Elastica\Request;
|
||||
use FOS\ElasticaBundle\Logger\ElasticaLogger;
|
||||
use FOS\ElasticaBundle\Transformer\CombinedResultTransformer;
|
||||
|
||||
/**
|
||||
* Extends the default Elastica client to provide logging for errors that occur
|
||||
|
@ -14,6 +15,38 @@ use FOS\ElasticaBundle\Logger\ElasticaLogger;
|
|||
*/
|
||||
class LoggingClient extends Client
|
||||
{
|
||||
/**
|
||||
* @var CombinedResultTransformer
|
||||
*/
|
||||
private $resultTransformer;
|
||||
|
||||
public function __construct(array $config = array(), $callback = null, CombinedResultTransformer $resultTransformer)
|
||||
{
|
||||
parent::__construct($config, $callback);
|
||||
|
||||
$this->resultTransformer = $resultTransformer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden Elastica method to return TransformingIndex instances instead of the
|
||||
* default Index instances.
|
||||
*
|
||||
* @param string $name
|
||||
* @return TransformingIndex
|
||||
*/
|
||||
public function getIndex($name)
|
||||
{
|
||||
return new TransformingIndex($this, $name, $this->resultTransformer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CombinedResultTransformer
|
||||
*/
|
||||
public function getResultTransformer()
|
||||
{
|
||||
return $this->resultTransformer;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -39,9 +72,4 @@ class LoggingClient extends Client
|
|||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function getIndex($name)
|
||||
{
|
||||
return new DynamicIndex($this, $name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Index;
|
||||
namespace FOS\ElasticaBundle\Elastica;
|
||||
|
||||
use Elastica\Client;
|
||||
use Elastica\Exception\InvalidException;
|
||||
use Elastica\Index;
|
||||
use FOS\ElasticaBundle\Transformer\CombinedResultTransformer;
|
||||
|
||||
/**
|
||||
* Overridden Elastica Index class that provides dynamic index name changes
|
||||
|
@ -14,20 +17,32 @@ use Elastica\Index;
|
|||
class TransformingIndex extends Index
|
||||
{
|
||||
/**
|
||||
* Indexes a
|
||||
* Creates a TransformingSearch instance instead of the default Elastica Search
|
||||
*
|
||||
* @param string $query
|
||||
* @param int|array $options
|
||||
* @return \Elastica\Search
|
||||
* @return TransformingSearch
|
||||
*/
|
||||
public function createSearch($query = '', $options = null)
|
||||
{
|
||||
$search = new Search($this->getClient());
|
||||
$search = new TransformingSearch($this->getClient());
|
||||
$search->addIndex($this);
|
||||
$search->setOptionsAndQuery($options, $query);
|
||||
|
||||
return $search;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a type object for the current index with the given name
|
||||
*
|
||||
* @param string $type Type name
|
||||
* @return TransformingType Type object
|
||||
*/
|
||||
public function getType($type)
|
||||
{
|
||||
return new TransformingType($this, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reassign index name
|
||||
*
|
||||
|
@ -35,8 +50,6 @@ class TransformingIndex extends Index
|
|||
* since it's used for a very specific case and normally should not be used
|
||||
*
|
||||
* @param string $name Index name
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function overrideName($name)
|
||||
{
|
||||
|
|
51
Elastica/TransformingResult.php
Normal file
51
Elastica/TransformingResult.php
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Elastica;
|
||||
|
||||
use Elastica\Result;
|
||||
|
||||
class TransformingResult extends Result
|
||||
{
|
||||
/**
|
||||
* The transformed hit.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
private $transformed;
|
||||
|
||||
/**
|
||||
* @var TransformingResultSet
|
||||
*/
|
||||
private $resultSet;
|
||||
|
||||
public function __construct(array $hit, TransformingResultSet $resultSet)
|
||||
{
|
||||
parent::__construct($hit);
|
||||
|
||||
$this->resultSet = $resultSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the transformed result of the hit.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getTransformed()
|
||||
{
|
||||
if (null === $this->transformed) {
|
||||
$this->resultSet->transform();
|
||||
}
|
||||
|
||||
return $this->transformed;
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal method used to set the transformed result on the Result.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function setTransformed($transformed)
|
||||
{
|
||||
$this->transformed = $transformed;
|
||||
}
|
||||
}
|
82
Elastica/TransformingResultSet.php
Normal file
82
Elastica/TransformingResultSet.php
Normal file
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Elastica;
|
||||
|
||||
use Elastica\Query;
|
||||
use Elastica\Response;
|
||||
use Elastica\ResultSet;
|
||||
use FOS\ElasticaBundle\Transformer\CombinedResultTransformer;
|
||||
use FOS\ElasticaBundle\Transformer\TransformerFactoryInterface;
|
||||
|
||||
class TransformingResultSet extends ResultSet
|
||||
{
|
||||
/**
|
||||
* @var \FOS\ElasticaBundle\Transformer\CombinedResultTransformer
|
||||
*/
|
||||
private $resultTransformer;
|
||||
|
||||
/**
|
||||
* If a transformation has already been performed on this ResultSet or not.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $transformed = false;
|
||||
|
||||
public function __construct(Response $response, Query $query, CombinedResultTransformer $resultTransformer)
|
||||
{
|
||||
parent::__construct($response, $query);
|
||||
|
||||
$this->resultTransformer = $resultTransformer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden default method to set our TransformingResult objects.
|
||||
*
|
||||
* @param \Elastica\Response $response Response object
|
||||
*/
|
||||
protected function _init(Response $response)
|
||||
{
|
||||
$this->_response = $response;
|
||||
$result = $response->getData();
|
||||
$this->_totalHits = isset($result['hits']['total']) ? $result['hits']['total'] : 0;
|
||||
$this->_maxScore = isset($result['hits']['max_score']) ? $result['hits']['max_score'] : 0;
|
||||
$this->_took = isset($result['took']) ? $result['took'] : 0;
|
||||
$this->_timedOut = !empty($result['timed_out']);
|
||||
if (isset($result['hits']['hits'])) {
|
||||
foreach ($result['hits']['hits'] as $hit) {
|
||||
$this->_results[] = new TransformingResult($hit, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of transformed results.
|
||||
*
|
||||
* @return object[]
|
||||
*/
|
||||
public function getTransformed()
|
||||
{
|
||||
$this->transform();
|
||||
|
||||
return array_map(function (TransformingResult $result) {
|
||||
return $result->getTransformed();
|
||||
}, $this->getResults());
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the transformation of all Results.
|
||||
*/
|
||||
public function transform()
|
||||
{
|
||||
if ($this->transformed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->count()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->resultTransformer->transform($this->getResults());
|
||||
$this->transformed = true;
|
||||
}
|
||||
}
|
73
Elastica/TransformingSearch.php
Normal file
73
Elastica/TransformingSearch.php
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Elastica;
|
||||
|
||||
use Elastica\Client;
|
||||
use Elastica\Request;
|
||||
use Elastica\Search;
|
||||
use FOS\ElasticaBundle\Transformer\CombinedResultTransformer;
|
||||
|
||||
/**
|
||||
* Overridden Elastica methods to return our TransformingResultSet
|
||||
*/
|
||||
class TransformingSearch extends Search
|
||||
{
|
||||
/**
|
||||
* Search in the set indices, types
|
||||
*
|
||||
* @param mixed $query
|
||||
* @param int|array $options OPTIONAL Limit or associative array of options (option=>value)
|
||||
* @throws \Elastica\Exception\InvalidException
|
||||
* @return TransformingResultSet
|
||||
*/
|
||||
public function search($query = '', $options = null)
|
||||
{
|
||||
$this->setOptionsAndQuery($options, $query);
|
||||
|
||||
$query = $this->getQuery();
|
||||
$path = $this->getPath();
|
||||
|
||||
$params = $this->getOptions();
|
||||
|
||||
// Send scroll_id via raw HTTP body to handle cases of very large (> 4kb) ids.
|
||||
if ('_search/scroll' == $path) {
|
||||
$data = $params[self::OPTION_SCROLL_ID];
|
||||
unset($params[self::OPTION_SCROLL_ID]);
|
||||
} else {
|
||||
$data = $query->toArray();
|
||||
}
|
||||
|
||||
$response = $this->getClient()->request(
|
||||
$path,
|
||||
Request::GET,
|
||||
$data,
|
||||
$params
|
||||
);
|
||||
|
||||
return new TransformingResultSet($response, $query, $this->_client->getResultTransformer());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param mixed $query
|
||||
* @param $fullResult (default = false) By default only the total hit count is returned. If set to true, the full ResultSet including facets is returned.
|
||||
* @return int|TransformingResultSet
|
||||
*/
|
||||
public function count($query = '', $fullResult = false)
|
||||
{
|
||||
$this->setOptionsAndQuery(null, $query);
|
||||
|
||||
$query = $this->getQuery();
|
||||
$path = $this->getPath();
|
||||
|
||||
$response = $this->getClient()->request(
|
||||
$path,
|
||||
Request::GET,
|
||||
$query->toArray(),
|
||||
array(self::OPTION_SEARCH_TYPE => self::OPTION_SEARCH_TYPE_COUNT)
|
||||
);
|
||||
$resultSet = new TransformingResultSet($response, $query, $this->_client->getResultTransformer());
|
||||
|
||||
return $fullResult ? $resultSet : $resultSet->getTotalHits();
|
||||
}
|
||||
}
|
25
Elastica/TransformingType.php
Normal file
25
Elastica/TransformingType.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Elastica;
|
||||
|
||||
use Elastica\Document;
|
||||
use Elastica\Query;
|
||||
use Elastica\Request;
|
||||
use Elastica\Type;
|
||||
|
||||
class TransformingType extends Type
|
||||
{
|
||||
/**
|
||||
* Overridden default method that returns our TransformingResultSet.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function moreLikeThis(Document $doc, $params = array(), $query = array())
|
||||
{
|
||||
$path = $doc->getId() . '/_mlt';
|
||||
$query = Query::create($query);
|
||||
$response = $this->request($path, Request::GET, $query->toArray(), $params);
|
||||
|
||||
return new TransformingResultSet($response, $query, $this->_index->getClient()->getResultTransformer());
|
||||
}
|
||||
}
|
15
Exception/MissingModelException.php
Normal file
15
Exception/MissingModelException.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
class MissingModelException extends \Exception
|
||||
{
|
||||
public function __construct($modelCount, $resultCount)
|
||||
{
|
||||
$message = sprintf('Expected to have %d models, but the lookup returned %d results', $resultCount, $modelCount);
|
||||
|
||||
parent::__construct($message);
|
||||
}
|
||||
}
|
13
Exception/UnexpectedObjectException.php
Normal file
13
Exception/UnexpectedObjectException.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
class UnexpectedObjectException extends \Exception
|
||||
{
|
||||
public function __construct($id)
|
||||
{
|
||||
parent::__construct(sprintf('Lookup returned an unknown object with id %d', $id));
|
||||
}
|
||||
}
|
54
Propel/Lookup.php
Normal file
54
Propel/Lookup.php
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Propel;
|
||||
|
||||
use Doctrine\Common\Util\Inflector;
|
||||
use FOS\ElasticaBundle\Type\LookupInterface;
|
||||
use FOS\ElasticaBundle\Type\TypeConfigurationInterface;
|
||||
|
||||
class Lookup implements LookupInterface
|
||||
{
|
||||
/**
|
||||
* Returns the lookup key.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getKey()
|
||||
{
|
||||
return 'propel';
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up objects of a specific type with ids as supplied.
|
||||
*
|
||||
* @param TypeConfigurationInterface $configuration
|
||||
* @param int[] $ids
|
||||
* @return object[]
|
||||
*/
|
||||
public function lookup(TypeConfigurationInterface $configuration, array $ids)
|
||||
{
|
||||
$query = $this->createQuery($configuration, $ids);
|
||||
|
||||
if (!$configuration->isHydrate()) {
|
||||
return $query->toArray();
|
||||
}
|
||||
|
||||
return $query->find();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query to use in the findByIdentifiers() method.
|
||||
*
|
||||
* @param TypeConfigurationInterface $configuration
|
||||
* @param array $ids
|
||||
* @return \ModelCriteria
|
||||
*/
|
||||
protected function createQuery(TypeConfigurationInterface $configuration, array $ids)
|
||||
{
|
||||
$queryClass = $configuration->getModelClass() . 'Query';
|
||||
$query = $queryClass::create();
|
||||
$filterMethod = 'filterBy' . Inflector::camelize($configuration->getIdentifierProperty());
|
||||
|
||||
return $query->$filterMethod($ids);
|
||||
}
|
||||
}
|
|
@ -4,9 +4,33 @@ namespace FOS\ElasticaBundle\Tests\Client;
|
|||
|
||||
use Elastica\Request;
|
||||
use Elastica\Transport\Null as NullTransport;
|
||||
use FOS\ElasticaBundle\Elastica\LoggingClient;
|
||||
|
||||
class LoggingClientTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testOverriddenElasticaMethods()
|
||||
{
|
||||
$resultTransformer = $this->getMockBuilder('FOS\ElasticaBundle\Transformer\CombinedResultTransformer')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$client = new LoggingClient(array(), null, $resultTransformer);
|
||||
$index = $client->getIndex('index');
|
||||
$type = $index->getType('type');
|
||||
|
||||
$this->assertInstanceOf('FOS\ElasticaBundle\Elastica\TransformingIndex', $index);
|
||||
$this->assertInstanceOf('FOS\ElasticaBundle\Elastica\TransformingType', $type);
|
||||
}
|
||||
|
||||
public function testGetResultTransformer()
|
||||
{
|
||||
$resultTransformer = $this->getMockBuilder('FOS\ElasticaBundle\Transformer\CombinedResultTransformer')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$client = new LoggingClient(array(), null, $resultTransformer);
|
||||
|
||||
$this->assertSame($resultTransformer, $client->getResultTransformer());
|
||||
}
|
||||
|
||||
public function testRequestsAreLogged()
|
||||
{
|
||||
$transport = new NullTransport;
|
||||
|
@ -29,6 +53,7 @@ class LoggingClientTest extends \PHPUnit_Framework_TestCase
|
|||
);
|
||||
|
||||
$client = $this->getMockBuilder('FOS\ElasticaBundle\Elastica\LoggingClient')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(array('getConnection'))
|
||||
->getMock();
|
||||
|
||||
|
|
42
Tests/Elastica/TransformingIndexTest.php
Normal file
42
Tests/Elastica/TransformingIndexTest.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Tests\Client;
|
||||
|
||||
use FOS\ElasticaBundle\Elastica\TransformingIndex;
|
||||
|
||||
class TransformingIndexTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var \FOS\ElasticaBundle\Elastica\TransformingIndex
|
||||
*/
|
||||
private $index;
|
||||
|
||||
/**
|
||||
* @var \FOS\ElasticaBundle\Elastica\LoggingClient
|
||||
*/
|
||||
private $client;
|
||||
|
||||
public function testCreateSearch()
|
||||
{
|
||||
$search = $this->index->createSearch();
|
||||
|
||||
$this->assertInstanceOf('FOS\ElasticaBundle\Elastica\TransformingSearch', $search);
|
||||
}
|
||||
|
||||
public function testOverrideName()
|
||||
{
|
||||
$this->assertEquals('testindex', $this->index->getName());
|
||||
|
||||
$this->index->overrideName('newindex');
|
||||
|
||||
$this->assertEquals('newindex', $this->index->getName());
|
||||
}
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->client = $this->getMockBuilder('FOS\ElasticaBundle\Elastica\LoggingClient')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->index = new TransformingIndex($this->client, 'testindex');
|
||||
}
|
||||
}
|
42
Tests/Elastica/TransformingResultSetTest.php
Normal file
42
Tests/Elastica/TransformingResultSetTest.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Tests\Client;
|
||||
|
||||
use Elastica\Query;
|
||||
use Elastica\Response;
|
||||
use FOS\ElasticaBundle\Elastica\TransformingResult;
|
||||
use FOS\ElasticaBundle\Elastica\TransformingResultSet;
|
||||
|
||||
class TransformingResultSetTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testTransformingResult()
|
||||
{
|
||||
$response = new Response(array('hits' => array(
|
||||
'hits' => array(
|
||||
array(),
|
||||
array(),
|
||||
array(),
|
||||
)
|
||||
)));
|
||||
$query = new Query();
|
||||
$transformer = $this->getMockBuilder('FOS\ElasticaBundle\Transformer\CombinedResultTransformer')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$resultSet = new TransformingResultSet($response, $query, $transformer);
|
||||
|
||||
$this->assertCount(3, $resultSet);
|
||||
$this->assertInstanceOf('FOS\ElasticaBundle\Elastica\TransformingResult', $resultSet[0]);
|
||||
|
||||
$transformer->expects($this->once())
|
||||
->method('transform')
|
||||
->with($resultSet->getResults());
|
||||
|
||||
$resultSet->transform();
|
||||
$resultSet->transform();
|
||||
|
||||
$this->assertSame(array(
|
||||
0 => null, 1 => null, 2 => null
|
||||
), $resultSet->getTransformed());
|
||||
}
|
||||
}
|
22
Tests/Elastica/TransformingResultTest.php
Normal file
22
Tests/Elastica/TransformingResultTest.php
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Tests\Client;
|
||||
|
||||
use FOS\ElasticaBundle\Elastica\TransformingResult;
|
||||
|
||||
class TransformingResultTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testTransformingResult()
|
||||
{
|
||||
$resultSet = $this->getMockBuilder('FOS\ElasticaBundle\Elastica\TransformingResultSet')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$result = new TransformingResult(array(), $resultSet);
|
||||
|
||||
$resultSet->expects($this->exactly(2))
|
||||
->method('transform');
|
||||
|
||||
$result->getTransformed();
|
||||
$result->getTransformed();
|
||||
}
|
||||
}
|
71
Transformer/CombinedResultTransformer.php
Normal file
71
Transformer/CombinedResultTransformer.php
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Transformer;
|
||||
|
||||
use FOS\ElasticaBundle\Elastica\TransformingResult;
|
||||
|
||||
/**
|
||||
* Transforms results from an index wide query with multiple types.
|
||||
*
|
||||
* @author Tim Nagel <tim@nagel.com.au>
|
||||
*/
|
||||
class CombinedResultTransformer
|
||||
{
|
||||
/**
|
||||
* @var \FOS\ElasticaBundle\Type\TypeConfigurationInterface
|
||||
*/
|
||||
private $configurations;
|
||||
|
||||
/**
|
||||
* @var ResultTransformerInterface
|
||||
*/
|
||||
private $transformer;
|
||||
|
||||
/**
|
||||
* @param \FOS\ElasticaBundle\Type\TypeConfigurationInterface[] $configurations
|
||||
* @param ResultTransformerInterface $transformer
|
||||
*/
|
||||
public function __construct(array $configurations, ResultTransformerInterface $transformer)
|
||||
{
|
||||
$this->configurations = $configurations;
|
||||
$this->transformer = $transformer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms Elastica results into Models.
|
||||
*
|
||||
* @param TransformingResult[] $results
|
||||
* @return object[]
|
||||
*/
|
||||
public function transform($results)
|
||||
{
|
||||
$grouped = array();
|
||||
|
||||
foreach ($results as $result) {
|
||||
$grouped[$result->getType()][] = $result;
|
||||
}
|
||||
|
||||
foreach ($grouped as $type => $group) {
|
||||
$this->transformer->transform($this->getConfiguration($type), $group);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the transformer for a given type.
|
||||
*
|
||||
* @param string $type
|
||||
* @return \FOS\ElasticaBundle\Type\TypeConfigurationInterface
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
private function getConfiguration($type)
|
||||
{
|
||||
if (!array_key_exists($type, $this->configurations)) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Configuration for type "%s" is not registered with this combined transformer.',
|
||||
$type
|
||||
));
|
||||
}
|
||||
|
||||
return $this->configurations[$type];
|
||||
}
|
||||
}
|
80
Transformer/ResultTransformer.php
Normal file
80
Transformer/ResultTransformer.php
Normal file
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Transformer;
|
||||
|
||||
use FOS\ElasticaBundle\Exception\MissingModelException;
|
||||
use FOS\ElasticaBundle\Exception\UnexpectedObjectException;
|
||||
use FOS\ElasticaBundle\Type\LookupManager;
|
||||
use FOS\ElasticaBundle\Type\TypeConfigurationInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
||||
|
||||
/**
|
||||
* Handles transforming results into models.
|
||||
*/
|
||||
class ResultTransformer implements ResultTransformerInterface
|
||||
{
|
||||
/**
|
||||
* @var \FOS\ElasticaBundle\Type\LookupManager
|
||||
*/
|
||||
private $lookupManager;
|
||||
|
||||
/**
|
||||
* @var \Symfony\Component\PropertyAccess\PropertyAccessorInterface
|
||||
*/
|
||||
private $propertyAccessor;
|
||||
|
||||
public function __construct(
|
||||
LookupManager $lookupManager,
|
||||
PropertyAccessorInterface $propertyAccessor
|
||||
) {
|
||||
$this->lookupManager = $lookupManager;
|
||||
$this->propertyAccessor = $propertyAccessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms Elastica results into Models.
|
||||
*
|
||||
* @param TypeConfigurationInterface $configuration
|
||||
* @param \FOS\ElasticaBundle\Elastica\TransformingResult[] $results
|
||||
* @throws \FOS\ElasticaBundle\Exception\MissingModelException
|
||||
* @throws \FOS\ElasticaBundle\Exception\UnexpectedObjectException
|
||||
*/
|
||||
public function transform(TypeConfigurationInterface $configuration, $results)
|
||||
{
|
||||
$results = $this->processResults($results);
|
||||
$lookup = $this->lookupManager->getLookup($configuration->getType());
|
||||
$objects = $lookup->lookup($configuration, array_keys($results));
|
||||
|
||||
if (!$configuration->isIgnoreMissing() and count($objects) < count($results)) {
|
||||
throw new MissingModelException(count($objects), count($results));
|
||||
}
|
||||
|
||||
$identifierProperty = $configuration->getIdentifierProperty();
|
||||
foreach ($objects as $object) {
|
||||
$id = $this->propertyAccessor->getValue($object, $identifierProperty);
|
||||
|
||||
if (!array_key_exists($id, $results)) {
|
||||
throw new UnexpectedObjectException($id);
|
||||
}
|
||||
|
||||
$results[$id]->setTransformed($object);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the results array into a more usable format for the transformation.
|
||||
*
|
||||
* @param \FOS\ElasticaBundle\Elastica\TransformingResult[] $results
|
||||
* @return \FOS\ElasticaBundle\Elastica\TransformingResult[]
|
||||
*/
|
||||
private function processResults($results)
|
||||
{
|
||||
$sorted = array();
|
||||
foreach ($results as $result) {
|
||||
$sorted[$result->getId()] = $result;
|
||||
}
|
||||
|
||||
return $sorted;
|
||||
}
|
||||
}
|
16
Transformer/ResultTransformerInterface.php
Normal file
16
Transformer/ResultTransformerInterface.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Transformer;
|
||||
|
||||
use FOS\ElasticaBundle\Type\TypeConfigurationInterface;
|
||||
|
||||
interface ResultTransformerInterface
|
||||
{
|
||||
/**
|
||||
* Transforms Elastica results into Models.
|
||||
*
|
||||
* @param TypeConfigurationInterface $configuration
|
||||
* @param array $results
|
||||
*/
|
||||
public function transform(TypeConfigurationInterface $configuration, $results);
|
||||
}
|
27
Type/LookupInterface.php
Normal file
27
Type/LookupInterface.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Type;
|
||||
|
||||
/**
|
||||
* A service that provides lookup capabilities for a type.
|
||||
*
|
||||
* @author Tim Nagel <tim@nagel.com.au>
|
||||
*/
|
||||
interface LookupInterface
|
||||
{
|
||||
/**
|
||||
* Returns the lookup key.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getKey();
|
||||
|
||||
/**
|
||||
* Look up objects of a specific type with ids as supplied.
|
||||
*
|
||||
* @param TypeConfigurationInterface $configuration
|
||||
* @param int[] $ids
|
||||
* @return object[]
|
||||
*/
|
||||
public function lookup(TypeConfigurationInterface $configuration, array $ids);
|
||||
}
|
36
Type/LookupManager.php
Normal file
36
Type/LookupManager.php
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Type;
|
||||
|
||||
class LookupManager
|
||||
{
|
||||
/**
|
||||
* @var LookupInterface[]
|
||||
*/
|
||||
private $lookups = array();
|
||||
|
||||
/**
|
||||
* @param LookupInterface[] $lookups
|
||||
*/
|
||||
public function __construct($lookups)
|
||||
{
|
||||
foreach ($lookups as $lookup) {
|
||||
$this->lookups[$lookup->getKey()] = $lookup;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @return LookupInterface
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getLookup($type)
|
||||
{
|
||||
if (!array_key_exists($type, $this->lookups)) {
|
||||
throw new \InvalidArgumentException(sprintf('Lookup with key "%s" does not exist', $type));
|
||||
}
|
||||
|
||||
return $this->lookups[$type];
|
||||
}
|
||||
}
|
54
Type/TypeConfigurationInterface.php
Normal file
54
Type/TypeConfigurationInterface.php
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
namespace FOS\ElasticaBundle\Type;
|
||||
|
||||
/**
|
||||
* A data object that contains configuration information about a specific type.
|
||||
*
|
||||
* @author Tim Nagel <tim@nagel.com.au>
|
||||
*/
|
||||
interface TypeConfigurationInterface
|
||||
{
|
||||
/**
|
||||
* The identifier property that is used to retrieve an identifier from the model.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifierProperty();
|
||||
|
||||
/**
|
||||
* Returns the fully qualified class for the model that this type represents.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getModelClass();
|
||||
|
||||
/**
|
||||
* Returns the repository method that will create a query builder or associated
|
||||
* query object for lookup purposes.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRepositoryMethod();
|
||||
|
||||
/**
|
||||
* Returns the name of the type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType();
|
||||
|
||||
/**
|
||||
* If the lookup should hydrate models to objects or leave data as an array.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isHydrate();
|
||||
|
||||
/**
|
||||
* If the type should ignore missing results from a lookup.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isIgnoreMissing();
|
||||
}
|
|
@ -12,6 +12,7 @@
|
|||
],
|
||||
"require": {
|
||||
"php": ">=5.3.2",
|
||||
"doctrine/inflector": "~1.0",
|
||||
"symfony/framework-bundle": "~2.3",
|
||||
"symfony/console": "~2.1",
|
||||
"symfony/form": "~2.1",
|
||||
|
|
Loading…
Reference in a new issue