Merge remote-tracking branch 'upstream/master'
Conflicts: Logger/ElasticaLogger.php README.md
This commit is contained in:
commit
41b347dfe4
|
@ -12,6 +12,15 @@ https://github.com/FriendsOfSymfony/FOSElasticaBundle/compare/v3.0.0...v3.0.1
|
||||||
To generate a changelog summary since the last version, run
|
To generate a changelog summary since the last version, run
|
||||||
`git log --no-merges --oneline v3.0.0...3.0.x`
|
`git log --no-merges --oneline v3.0.0...3.0.x`
|
||||||
|
|
||||||
* 3.0.0-ALPHA2 (2014-xx-xx)
|
* 3.0.0-ALPHA3 (xxxx-xx-xx)
|
||||||
|
|
||||||
|
* #463: allowing hot swappable reindexing
|
||||||
|
* #415: BC BREAK: document indexing occurs in postFlush rather than the pre* events previously.
|
||||||
|
* 7d13823: Dropped (broken) support for Symfony <2.3
|
||||||
|
|
||||||
|
* 3.0.0-ALPHA2 (2014-03-17)
|
||||||
|
|
||||||
* 41bf07e: Renamed the `no-stop-on-error` option in PopulateCommand to `ignore-errors`
|
* 41bf07e: Renamed the `no-stop-on-error` option in PopulateCommand to `ignore-errors`
|
||||||
|
* 418b9d7: Fixed validation of url configuration
|
||||||
|
* 726892c: Ignore TypeMissingException when resetting a single type. This allows to create new types without having to recreate the whole index.
|
||||||
|
* 7f53bad Add support for include_in_{parent,root} for nested and objects
|
||||||
|
|
|
@ -33,4 +33,9 @@ class Client extends ElasticaClient
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getIndex($name)
|
||||||
|
{
|
||||||
|
return new DynamicIndex($this, $name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,6 +126,7 @@ class PopulateCommand extends ContainerAwareCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
$output->writeln(sprintf('<info>Refreshing</info> <comment>%s</comment>', $index));
|
$output->writeln(sprintf('<info>Refreshing</info> <comment>%s</comment>', $index));
|
||||||
|
$this->resetter->postPopulate($index);
|
||||||
$this->indexManager->getIndex($index)->refresh();
|
$this->indexManager->getIndex($index)->refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -146,6 +146,7 @@ class Configuration implements ConfigurationInterface
|
||||||
->prototype('array')
|
->prototype('array')
|
||||||
->children()
|
->children()
|
||||||
->scalarNode('index_name')->end()
|
->scalarNode('index_name')->end()
|
||||||
|
->booleanNode('use_alias')->defaultValue(false)->end()
|
||||||
->scalarNode('client')->end()
|
->scalarNode('client')->end()
|
||||||
->scalarNode('finder')
|
->scalarNode('finder')
|
||||||
->treatNullLike(true)
|
->treatNullLike(true)
|
||||||
|
@ -183,6 +184,7 @@ class Configuration implements ConfigurationInterface
|
||||||
->scalarNode('insert')->defaultTrue()->end()
|
->scalarNode('insert')->defaultTrue()->end()
|
||||||
->scalarNode('update')->defaultTrue()->end()
|
->scalarNode('update')->defaultTrue()->end()
|
||||||
->scalarNode('delete')->defaultTrue()->end()
|
->scalarNode('delete')->defaultTrue()->end()
|
||||||
|
->scalarNode('persist')->defaultValue('postFlush')->end()
|
||||||
->scalarNode('service')->end()
|
->scalarNode('service')->end()
|
||||||
->variableNode('is_indexable_callback')->defaultNull()->end()
|
->variableNode('is_indexable_callback')->defaultNull()->end()
|
||||||
->end()
|
->end()
|
||||||
|
@ -275,6 +277,7 @@ class Configuration implements ConfigurationInterface
|
||||||
->scalarNode('insert')->defaultTrue()->end()
|
->scalarNode('insert')->defaultTrue()->end()
|
||||||
->scalarNode('update')->defaultTrue()->end()
|
->scalarNode('update')->defaultTrue()->end()
|
||||||
->scalarNode('delete')->defaultTrue()->end()
|
->scalarNode('delete')->defaultTrue()->end()
|
||||||
|
->booleanNode('immediate')->defaultFalse()->end()
|
||||||
->scalarNode('service')->end()
|
->scalarNode('service')->end()
|
||||||
->variableNode('is_indexable_callback')->defaultNull()->end()
|
->variableNode('is_indexable_callback')->defaultNull()->end()
|
||||||
->end()
|
->end()
|
||||||
|
@ -421,6 +424,10 @@ class Configuration implements ConfigurationInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($nestings['properties'])) {
|
if (isset($nestings['properties'])) {
|
||||||
|
$node
|
||||||
|
->booleanNode('include_in_parent')->end()
|
||||||
|
->booleanNode('include_in_root')->end()
|
||||||
|
;
|
||||||
$this->addNestedFieldConfig($node, $nestings, 'properties');
|
$this->addNestedFieldConfig($node, $nestings, 'properties');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace FOS\ElasticaBundle\DependencyInjection;
|
||||||
|
|
||||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
||||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
use Symfony\Component\DependencyInjection\Definition;
|
use Symfony\Component\DependencyInjection\Definition;
|
||||||
use Symfony\Component\DependencyInjection\DefinitionDecorator;
|
use Symfony\Component\DependencyInjection\DefinitionDecorator;
|
||||||
|
@ -124,6 +125,7 @@ class FOSElasticaExtension extends Extension
|
||||||
$indexIds[$name] = $indexId;
|
$indexIds[$name] = $indexId;
|
||||||
$this->indexConfigs[$name] = array(
|
$this->indexConfigs[$name] = array(
|
||||||
'index' => new Reference($indexId),
|
'index' => new Reference($indexId),
|
||||||
|
'name_or_alias' => $indexName,
|
||||||
'config' => array(
|
'config' => array(
|
||||||
'mappings' => array()
|
'mappings' => array()
|
||||||
)
|
)
|
||||||
|
@ -134,6 +136,10 @@ class FOSElasticaExtension extends Extension
|
||||||
if (!empty($index['settings'])) {
|
if (!empty($index['settings'])) {
|
||||||
$this->indexConfigs[$name]['config']['settings'] = $index['settings'];
|
$this->indexConfigs[$name]['config']['settings'] = $index['settings'];
|
||||||
}
|
}
|
||||||
|
if ($index['use_alias']) {
|
||||||
|
$this->indexConfigs[$name]['use_alias'] = true;
|
||||||
|
}
|
||||||
|
|
||||||
$this->loadTypes(isset($index['types']) ? $index['types'] : array(), $container, $name, $indexId, $typePrototypeConfig);
|
$this->loadTypes(isset($index['types']) ? $index['types'] : array(), $container, $name, $indexId, $typePrototypeConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,6 +204,10 @@ class FOSElasticaExtension extends Extension
|
||||||
if (isset($type['serializer']['version'])) {
|
if (isset($type['serializer']['version'])) {
|
||||||
$callbackDef->addMethodCall('setVersion', array($type['serializer']['version']));
|
$callbackDef->addMethodCall('setVersion', array($type['serializer']['version']));
|
||||||
}
|
}
|
||||||
|
$callbackClassImplementedInterfaces = class_implements($this->serializerConfig['callback_class']); // PHP < 5.4 friendly
|
||||||
|
if (isset($callbackClassImplementedInterfaces['Symfony\Component\DependencyInjection\ContainerAwareInterface'])) {
|
||||||
|
$callbackDef->addMethodCall('setContainer', array(new Reference('service_container')));
|
||||||
|
}
|
||||||
|
|
||||||
$container->setDefinition($callbackId, $callbackDef);
|
$container->setDefinition($callbackId, $callbackDef);
|
||||||
|
|
||||||
|
@ -443,13 +453,32 @@ class FOSElasticaExtension extends Extension
|
||||||
return $listenerId;
|
return $listenerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map Elastica to Doctrine events for the current driver
|
||||||
|
*/
|
||||||
private function getDoctrineEvents(array $typeConfig)
|
private function getDoctrineEvents(array $typeConfig)
|
||||||
{
|
{
|
||||||
|
// Flush always calls depending on actions scheduled in lifecycle listeners
|
||||||
|
$typeConfig['listener']['flush'] = true;
|
||||||
|
|
||||||
|
switch ($typeConfig['driver']) {
|
||||||
|
case 'orm':
|
||||||
|
$eventsClass = '\Doctrine\ORM\Events';
|
||||||
|
break;
|
||||||
|
case 'mongodb':
|
||||||
|
$eventsClass = '\Doctrine\ODM\MongoDB\Events';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidArgumentException(sprintf('Cannot determine events for driver "%s"', $typeConfig['driver']));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
$events = array();
|
$events = array();
|
||||||
$eventMapping = array(
|
$eventMapping = array(
|
||||||
'insert' => array('postPersist'),
|
'insert' => array(constant($eventsClass.'::postPersist')),
|
||||||
'update' => array('postUpdate'),
|
'update' => array(constant($eventsClass.'::postUpdate')),
|
||||||
'delete' => array('postRemove', 'preRemove')
|
'delete' => array(constant($eventsClass.'::preRemove')),
|
||||||
|
'flush' => array($typeConfig['listener']['immediate'] ? constant($eventsClass.'::preFlush') : constant($eventsClass.'::postFlush'))
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach ($eventMapping as $event => $doctrineEvents) {
|
foreach ($eventMapping as $event => $doctrineEvents) {
|
||||||
|
|
|
@ -2,15 +2,15 @@
|
||||||
|
|
||||||
namespace FOS\ElasticaBundle\Doctrine;
|
namespace FOS\ElasticaBundle\Doctrine;
|
||||||
|
|
||||||
|
use Doctrine\Common\EventArgs;
|
||||||
use Doctrine\Common\EventSubscriber;
|
use Doctrine\Common\EventSubscriber;
|
||||||
use Doctrine\Common\Persistence\ObjectManager;
|
|
||||||
use FOS\ElasticaBundle\Persister\ObjectPersisterInterface;
|
use FOS\ElasticaBundle\Persister\ObjectPersisterInterface;
|
||||||
use FOS\ElasticaBundle\Persister\ObjectPersister;
|
use FOS\ElasticaBundle\Persister\ObjectPersister;
|
||||||
use Symfony\Component\ExpressionLanguage\Expression;
|
use Symfony\Component\ExpressionLanguage\Expression;
|
||||||
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
|
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
|
||||||
use Symfony\Component\ExpressionLanguage\SyntaxError;
|
use Symfony\Component\ExpressionLanguage\SyntaxError;
|
||||||
|
|
||||||
abstract class AbstractListener implements EventSubscriber
|
class Listener implements EventSubscriber
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Object persister
|
* Object persister
|
||||||
|
@ -48,11 +48,11 @@ abstract class AbstractListener implements EventSubscriber
|
||||||
protected $isIndexableCallback;
|
protected $isIndexableCallback;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Objects scheduled for removal
|
* Objects scheduled for insertion, replacement, or removal
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
*/
|
||||||
private $scheduledForRemoval = array();
|
public $scheduledForInsertion = array();
|
||||||
|
public $scheduledForUpdate = array();
|
||||||
|
public $scheduledForDeletion = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An instance of ExpressionLanguage
|
* An instance of ExpressionLanguage
|
||||||
|
@ -149,37 +149,6 @@ abstract class AbstractListener implements EventSubscriber
|
||||||
: call_user_func($this->isIndexableCallback, $object);
|
: call_user_func($this->isIndexableCallback, $object);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Schedules the object for removal.
|
|
||||||
*
|
|
||||||
* This is usually called during the pre-remove event.
|
|
||||||
*
|
|
||||||
* @param object $object
|
|
||||||
* @param ObjectManager $objectManager
|
|
||||||
*/
|
|
||||||
protected function scheduleForRemoval($object, ObjectManager $objectManager)
|
|
||||||
{
|
|
||||||
$metadata = $objectManager->getClassMetadata($this->objectClass);
|
|
||||||
$esId = $metadata->getFieldValue($object, $this->esIdentifierField);
|
|
||||||
$this->scheduledForRemoval[spl_object_hash($object)] = $esId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the object if it was scheduled for removal.
|
|
||||||
*
|
|
||||||
* This is usually called during the post-remove event.
|
|
||||||
*
|
|
||||||
* @param object $object
|
|
||||||
*/
|
|
||||||
protected function removeIfScheduled($object)
|
|
||||||
{
|
|
||||||
$objectHash = spl_object_hash($object);
|
|
||||||
if (isset($this->scheduledForRemoval[$objectHash])) {
|
|
||||||
$this->objectPersister->deleteById($this->scheduledForRemoval[$objectHash]);
|
|
||||||
unset($this->scheduledForRemoval[$objectHash]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param mixed $object
|
* @param mixed $object
|
||||||
* @return string
|
* @return string
|
||||||
|
@ -207,4 +176,70 @@ abstract class AbstractListener implements EventSubscriber
|
||||||
|
|
||||||
return $this->expressionLanguage;
|
return $this->expressionLanguage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function postPersist(EventArgs $eventArgs)
|
||||||
|
{
|
||||||
|
$entity = $eventArgs->getEntity();
|
||||||
|
|
||||||
|
if ($entity instanceof $this->objectClass && $this->isObjectIndexable($entity)) {
|
||||||
|
$this->scheduledForInsertion[] = $entity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function postUpdate(EventArgs $eventArgs)
|
||||||
|
{
|
||||||
|
$entity = $eventArgs->getEntity();
|
||||||
|
|
||||||
|
if ($entity instanceof $this->objectClass) {
|
||||||
|
if ($this->isObjectIndexable($entity)) {
|
||||||
|
$this->scheduledForUpdate[] = $entity;
|
||||||
|
} else {
|
||||||
|
// Delete if no longer indexable
|
||||||
|
$this->scheduledForDeletion[] = $entity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function preRemove(EventArgs $eventArgs)
|
||||||
|
{
|
||||||
|
$entity = $eventArgs->getEntity();
|
||||||
|
|
||||||
|
if ($entity instanceof $this->objectClass) {
|
||||||
|
$this->scheduledForDeletion[] = $entity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Persist scheduled objects to ElasticSearch
|
||||||
|
*/
|
||||||
|
private function persistScheduled()
|
||||||
|
{
|
||||||
|
if (count($this->scheduledForInsertion)) {
|
||||||
|
$this->objectPersister->insertMany($this->scheduledForInsertion);
|
||||||
|
}
|
||||||
|
if (count($this->scheduledForUpdate)) {
|
||||||
|
$this->objectPersister->replaceMany($this->scheduledForUpdate);
|
||||||
|
}
|
||||||
|
if (count($this->scheduledForDeletion)) {
|
||||||
|
$this->objectPersister->deleteMany($this->scheduledForDeletion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterate through scheduled actions before flushing to emulate 2.x behavior. Note that the ElasticSearch index
|
||||||
|
* will fall out of sync with the source data in the event of a crash during flush.
|
||||||
|
*/
|
||||||
|
public function preFlush(EventArgs $eventArgs)
|
||||||
|
{
|
||||||
|
$this->persistScheduled();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterating through scheduled actions *after* flushing ensures that the ElasticSearch index will be affected
|
||||||
|
* only if the query is successful
|
||||||
|
*/
|
||||||
|
public function postFlush(EventArgs $eventArgs)
|
||||||
|
{
|
||||||
|
$this->persistScheduled();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,50 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace FOS\ElasticaBundle\Doctrine\MongoDB;
|
|
||||||
|
|
||||||
use Doctrine\ODM\MongoDB\Event\LifecycleEventArgs;
|
|
||||||
use FOS\ElasticaBundle\Doctrine\AbstractListener;
|
|
||||||
|
|
||||||
class Listener extends AbstractListener
|
|
||||||
{
|
|
||||||
public function postPersist(LifecycleEventArgs $eventArgs)
|
|
||||||
{
|
|
||||||
$document = $eventArgs->getDocument();
|
|
||||||
|
|
||||||
if ($document instanceof $this->objectClass && $this->isObjectIndexable($document)) {
|
|
||||||
$this->objectPersister->insertOne($document);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function postUpdate(LifecycleEventArgs $eventArgs)
|
|
||||||
{
|
|
||||||
$document = $eventArgs->getDocument();
|
|
||||||
|
|
||||||
if ($document instanceof $this->objectClass) {
|
|
||||||
if ($this->isObjectIndexable($document)) {
|
|
||||||
$this->objectPersister->replaceOne($document);
|
|
||||||
} else {
|
|
||||||
$this->scheduleForRemoval($document, $eventArgs->getDocumentManager());
|
|
||||||
$this->removeIfScheduled($document);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function preRemove(LifecycleEventArgs $eventArgs)
|
|
||||||
{
|
|
||||||
$document = $eventArgs->getDocument();
|
|
||||||
|
|
||||||
if ($document instanceof $this->objectClass) {
|
|
||||||
$this->scheduleForRemoval($document, $eventArgs->getDocumentManager());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function postRemove(LifecycleEventArgs $eventArgs)
|
|
||||||
{
|
|
||||||
$document = $eventArgs->getDocument();
|
|
||||||
|
|
||||||
if ($document instanceof $this->objectClass) {
|
|
||||||
$this->removeIfScheduled($document);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace FOS\ElasticaBundle\Doctrine\ORM;
|
|
||||||
|
|
||||||
use Doctrine\ORM\Event\LifecycleEventArgs;
|
|
||||||
use FOS\ElasticaBundle\Doctrine\AbstractListener;
|
|
||||||
|
|
||||||
class Listener extends AbstractListener
|
|
||||||
{
|
|
||||||
public function postPersist(LifecycleEventArgs $eventArgs)
|
|
||||||
{
|
|
||||||
$entity = $eventArgs->getEntity();
|
|
||||||
|
|
||||||
if ($entity instanceof $this->objectClass && $this->isObjectIndexable($entity)) {
|
|
||||||
$this->objectPersister->insertOne($entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function postUpdate(LifecycleEventArgs $eventArgs)
|
|
||||||
{
|
|
||||||
$entity = $eventArgs->getEntity();
|
|
||||||
|
|
||||||
if ($entity instanceof $this->objectClass) {
|
|
||||||
if ($this->isObjectIndexable($entity)) {
|
|
||||||
$this->objectPersister->replaceOne($entity);
|
|
||||||
} else {
|
|
||||||
$this->scheduleForRemoval($entity, $eventArgs->getEntityManager());
|
|
||||||
$this->removeIfScheduled($entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function preRemove(LifecycleEventArgs $eventArgs)
|
|
||||||
{
|
|
||||||
$entity = $eventArgs->getEntity();
|
|
||||||
|
|
||||||
if ($entity instanceof $this->objectClass) {
|
|
||||||
$this->scheduleForRemoval($entity, $eventArgs->getEntityManager());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function postRemove(LifecycleEventArgs $eventArgs)
|
|
||||||
{
|
|
||||||
$entity = $eventArgs->getEntity();
|
|
||||||
|
|
||||||
if ($entity instanceof $this->objectClass) {
|
|
||||||
$this->removeIfScheduled($entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
28
DynamicIndex.php
Normal file
28
DynamicIndex.php
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FOS\ElasticaBundle;
|
||||||
|
|
||||||
|
use Elastica\Index;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elastica index capable of reassigning name dynamically
|
||||||
|
*
|
||||||
|
* @author Konstantin Tjuterev <kostik.lv@gmail.com>
|
||||||
|
*/
|
||||||
|
class DynamicIndex extends Index
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Reassign index name
|
||||||
|
*
|
||||||
|
* While it's technically a regular setter for name property, it's specifically named overrideName, but not setName
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
$this->_name = $name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,32 +14,42 @@ use Psr\Log\LoggerInterface;
|
||||||
*/
|
*/
|
||||||
class ElasticaLogger implements LoggerInterface
|
class ElasticaLogger implements LoggerInterface
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @var LoggerInterface
|
||||||
|
*/
|
||||||
protected $logger;
|
protected $logger;
|
||||||
protected $queries;
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $queries = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
protected $debug;
|
protected $debug;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param LoggerInterface|null $logger The Symfony logger
|
* @param LoggerInterface|null $logger The Symfony logger
|
||||||
* @param bool $debug
|
* @param boolean $debug
|
||||||
*/
|
*/
|
||||||
public function __construct(LoggerInterface $logger = null, $debug = false)
|
public function __construct(LoggerInterface $logger = null, $debug = false)
|
||||||
{
|
{
|
||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
$this->queries = array();
|
|
||||||
$this->debug = $debug;
|
$this->debug = $debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs a query.
|
* Logs a query.
|
||||||
*
|
*
|
||||||
* @param string $path Path to call
|
* @param string $path Path to call
|
||||||
* @param string $method Rest method to use (GET, POST, DELETE, PUT)
|
* @param string $method Rest method to use (GET, POST, DELETE, PUT)
|
||||||
* @param array $data arguments
|
* @param array $data Arguments
|
||||||
* @param float $time execution time
|
* @param float $time Execution time
|
||||||
* @param array $connection host, port, transport and headers of the query
|
* @param array $connection Host, port, transport, and headers of the query
|
||||||
* @param array $query arguments
|
* @param array $query Arguments
|
||||||
*/
|
*/
|
||||||
public function logQuery($path, $method, $data, $time, $connection = array(), $query = array())
|
public function logQuery($path, $method, $data, $time, $connection = array(), $query = array())
|
||||||
{
|
{
|
||||||
|
|
|
@ -33,7 +33,7 @@ class RawPaginatorAdapter implements PaginatorAdapterInterface
|
||||||
private $totalHits;
|
private $totalHits;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @array for the facets
|
* @var array for the facets
|
||||||
*/
|
*/
|
||||||
private $facets;
|
private $facets;
|
||||||
|
|
||||||
|
|
|
@ -83,12 +83,12 @@ class ObjectPersister implements ObjectPersisterInterface
|
||||||
} catch (NotFoundException $e) {}
|
} catch (NotFoundException $e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts an array of objects in the type
|
* Bulk insert an array of objects in the type for the given method
|
||||||
*
|
*
|
||||||
* @param array $objects array of domain model objects
|
* @param array $objects array of domain model objects
|
||||||
**/
|
* @param string Method to call
|
||||||
|
*/
|
||||||
public function insertMany(array $objects)
|
public function insertMany(array $objects)
|
||||||
{
|
{
|
||||||
$documents = array();
|
$documents = array();
|
||||||
|
@ -98,6 +98,34 @@ class ObjectPersister implements ObjectPersisterInterface
|
||||||
$this->type->addDocuments($documents);
|
$this->type->addDocuments($documents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bulk updates an array of objects in the type
|
||||||
|
*
|
||||||
|
* @param array $objects array of domain model objects
|
||||||
|
*/
|
||||||
|
public function replaceMany(array $objects)
|
||||||
|
{
|
||||||
|
$documents = array();
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
$documents[] = $this->transformToElasticaDocument($object);
|
||||||
|
}
|
||||||
|
$this->type->updateDocuments($documents);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bulk deletes an array of objects in the type
|
||||||
|
*
|
||||||
|
* @param array $objects array of domain model objects
|
||||||
|
*/
|
||||||
|
public function deleteMany(array $objects)
|
||||||
|
{
|
||||||
|
$documents = array();
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
$documents[] = $this->transformToElasticaDocument($object);
|
||||||
|
}
|
||||||
|
$this->type->deleteDocuments($documents);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms an object to an elastica document
|
* Transforms an object to an elastica document
|
||||||
*
|
*
|
||||||
|
|
|
@ -38,13 +38,27 @@ interface ObjectPersisterInterface
|
||||||
* @param mixed $id
|
* @param mixed $id
|
||||||
*
|
*
|
||||||
* @return null
|
* @return null
|
||||||
**/
|
*/
|
||||||
function deleteById($id);
|
function deleteById($id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts an array of objects in the type
|
* Bulk inserts an array of objects in the type
|
||||||
*
|
*
|
||||||
* @param array $objects array of domain model objects
|
* @param array $objects array of domain model objects
|
||||||
**/
|
*/
|
||||||
function insertMany(array $objects);
|
function insertMany(array $objects);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bulk updates an array of objects in the type
|
||||||
|
*
|
||||||
|
* @param array $objects array of domain model objects
|
||||||
|
*/
|
||||||
|
function replaceMany(array $objects);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bulk deletes an array of objects in the type
|
||||||
|
*
|
||||||
|
* @param array $objects array of domain model objects
|
||||||
|
*/
|
||||||
|
function deleteMany(array $objects);
|
||||||
}
|
}
|
||||||
|
|
24
README.md
24
README.md
|
@ -76,6 +76,8 @@ A sample configuration with Basic HTTP Authentication is:
|
||||||
headers:
|
headers:
|
||||||
Authorization: "Basic jdumrGK7rY9TMuQOPng7GZycmxyMHNoir=="
|
Authorization: "Basic jdumrGK7rY9TMuQOPng7GZycmxyMHNoir=="
|
||||||
|
|
||||||
|
A client configuration can also override the Elastica logger to change the used class ```logger: <your logger class>``` or to simply disable it ```logger: false```. Disabling the logger should be done on production because it can cause a memory leak.
|
||||||
|
|
||||||
#### Declare a serializer
|
#### Declare a serializer
|
||||||
|
|
||||||
Elastica can handle objects instead of data arrays if a serializer callable is configured
|
Elastica can handle objects instead of data arrays if a serializer callable is configured
|
||||||
|
@ -601,7 +603,11 @@ class User
|
||||||
### Realtime, selective index update
|
### Realtime, selective index update
|
||||||
|
|
||||||
If you use the Doctrine integration, you can let ElasticaBundle update the indexes automatically
|
If you use the Doctrine integration, you can let ElasticaBundle update the indexes automatically
|
||||||
when an object is added, updated or removed. It uses Doctrine lifecycle events.
|
when an object is added, updated or removed. It uses Doctrine lifecycle events to schedule updates
|
||||||
|
and then synchronizes changes either before or after flush.
|
||||||
|
|
||||||
|
> **Propel** doesn't support this feature yet.
|
||||||
|
|
||||||
Declare that you want to update the index in real time:
|
Declare that you want to update the index in real time:
|
||||||
|
|
||||||
fos_elastica:
|
fos_elastica:
|
||||||
|
@ -617,7 +623,7 @@ Declare that you want to update the index in real time:
|
||||||
persistence:
|
persistence:
|
||||||
driver: orm
|
driver: orm
|
||||||
model: Application\UserBundle\Entity\User
|
model: Application\UserBundle\Entity\User
|
||||||
listener: ~ # by default, listens to "insert", "update" and "delete"
|
listener: ~ # by default, listens to "insert", "update" and "delete" and updates `postFlush`
|
||||||
|
|
||||||
Now the index is automatically updated each time the state of the bound Doctrine repository changes.
|
Now the index is automatically updated each time the state of the bound Doctrine repository changes.
|
||||||
No need to repopulate the whole "user" index when a new `User` is created.
|
No need to repopulate the whole "user" index when a new `User` is created.
|
||||||
|
@ -630,7 +636,19 @@ You can also choose to only listen for some of the events:
|
||||||
update: false
|
update: false
|
||||||
delete: true
|
delete: true
|
||||||
|
|
||||||
> **Propel** doesn't support this feature yet.
|
By default, the ElasticSearch index will be updated after flush. To update before flushing, set `immediate`
|
||||||
|
to `true`:
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
listener:
|
||||||
|
insert: true
|
||||||
|
update: false
|
||||||
|
delete: true
|
||||||
|
immediate: true
|
||||||
|
|
||||||
|
> Using `immediate` to update ElasticSearch before flush completes may cause the ElasticSearch index to fall out of
|
||||||
|
> sync with the source database in the event of a crash during the flush itself, such as in the case of a bad query.
|
||||||
|
|
||||||
|
|
||||||
### Checking an entity method for listener
|
### Checking an entity method for listener
|
||||||
|
|
||||||
|
|
145
Resetter.php
145
Resetter.php
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
namespace FOS\ElasticaBundle;
|
namespace FOS\ElasticaBundle;
|
||||||
|
|
||||||
|
use Elastica\Exception\ExceptionInterface;
|
||||||
|
use Elastica\Index;
|
||||||
|
use Elastica\Exception\ResponseException;
|
||||||
use Elastica\Type\Mapping;
|
use Elastica\Type\Mapping;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,8 +29,8 @@ class Resetter
|
||||||
*/
|
*/
|
||||||
public function resetAllIndexes()
|
public function resetAllIndexes()
|
||||||
{
|
{
|
||||||
foreach ($this->indexConfigsByName as $indexConfig) {
|
foreach (array_keys($this->indexConfigsByName) as $name) {
|
||||||
$indexConfig['index']->create($indexConfig['config'], true);
|
$this->resetIndex($name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +43,17 @@ class Resetter
|
||||||
public function resetIndex($indexName)
|
public function resetIndex($indexName)
|
||||||
{
|
{
|
||||||
$indexConfig = $this->getIndexConfig($indexName);
|
$indexConfig = $this->getIndexConfig($indexName);
|
||||||
$indexConfig['index']->create($indexConfig['config'], true);
|
$esIndex = $indexConfig['index'];
|
||||||
|
if (isset($indexConfig['use_alias']) && $indexConfig['use_alias']) {
|
||||||
|
$name = $indexConfig['name_or_alias'];
|
||||||
|
$name .= uniqid();
|
||||||
|
$esIndex->overrideName($name);
|
||||||
|
$esIndex->create($indexConfig['config']);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$esIndex->create($indexConfig['config'], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -59,7 +72,13 @@ class Resetter
|
||||||
}
|
}
|
||||||
|
|
||||||
$type = $indexConfig['index']->getType($typeName);
|
$type = $indexConfig['index']->getType($typeName);
|
||||||
$type->delete();
|
try {
|
||||||
|
$type->delete();
|
||||||
|
} catch (ResponseException $e) {
|
||||||
|
if (strpos($e->getMessage(), 'TypeMissingException') === false) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
$mapping = $this->createMapping($indexConfig['config']['mappings'][$typeName]);
|
$mapping = $this->createMapping($indexConfig['config']['mappings'][$typeName]);
|
||||||
$type->setMapping($mapping);
|
$type->setMapping($mapping);
|
||||||
}
|
}
|
||||||
|
@ -105,4 +124,122 @@ class Resetter
|
||||||
|
|
||||||
return $this->indexConfigsByName[$indexName];
|
return $this->indexConfigsByName[$indexName];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function postPopulate($indexName)
|
||||||
|
{
|
||||||
|
$indexConfig = $this->getIndexConfig($indexName);
|
||||||
|
if (isset($indexConfig['use_alias']) && $indexConfig['use_alias']) {
|
||||||
|
$this->switchIndexAlias($indexName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switches the alias for given index (by key) to the newly populated index
|
||||||
|
* and deletes the old index
|
||||||
|
*
|
||||||
|
* @param string $indexName Index name
|
||||||
|
*
|
||||||
|
* @throws \RuntimeException
|
||||||
|
*/
|
||||||
|
private function switchIndexAlias($indexName)
|
||||||
|
{
|
||||||
|
$indexConfig = $this->getIndexConfig($indexName);
|
||||||
|
$esIndex = $indexConfig['index'];
|
||||||
|
$aliasName = $indexConfig['name_or_alias'];
|
||||||
|
$oldIndexName = false;
|
||||||
|
$newIndexName = $esIndex->getName();
|
||||||
|
|
||||||
|
$aliasedIndexes = $this->getAliasedIndexes($esIndex, $aliasName);
|
||||||
|
|
||||||
|
if (count($aliasedIndexes) > 1) {
|
||||||
|
throw new \RuntimeException(
|
||||||
|
sprintf(
|
||||||
|
'Alias %s is used for multiple indexes: [%s].
|
||||||
|
Make sure it\'s either not used or is assigned to one index only',
|
||||||
|
$aliasName,
|
||||||
|
join(', ', $aliasedIndexes)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change the alias to point to the new index
|
||||||
|
// Elastica's addAlias can't be used directly, because in current (0.19.x) version it's not atomic
|
||||||
|
// In 0.20.x it's atomic, but it doesn't return the old index name
|
||||||
|
$aliasUpdateRequest = array('actions' => array());
|
||||||
|
if (count($aliasedIndexes) == 1) {
|
||||||
|
// if the alias is set - add an action to remove it
|
||||||
|
$oldIndexName = $aliasedIndexes[0];
|
||||||
|
$aliasUpdateRequest['actions'][] = array(
|
||||||
|
'remove' => array('index' => $oldIndexName, 'alias' => $aliasName)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add an action to point the alias to the new index
|
||||||
|
$aliasUpdateRequest['actions'][] = array(
|
||||||
|
'add' => array('index' => $newIndexName, 'alias' => $aliasName)
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$esIndex->getClient()->request('_aliases', 'POST', $aliasUpdateRequest);
|
||||||
|
} catch (ExceptionInterface $renameAliasException) {
|
||||||
|
$additionalError = '';
|
||||||
|
// if we failed to move the alias, delete the newly built index
|
||||||
|
try {
|
||||||
|
$esIndex->delete();
|
||||||
|
} catch (ExceptionInterface $deleteNewIndexException) {
|
||||||
|
$additionalError = sprintf(
|
||||||
|
'Tried to delete newly built index %s, but also failed: %s',
|
||||||
|
$newIndexName,
|
||||||
|
$deleteNewIndexException->getError()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \RuntimeException(
|
||||||
|
sprintf(
|
||||||
|
'Failed to updated index alias: %s. %s',
|
||||||
|
$renameAliasException->getMessage(),
|
||||||
|
$additionalError ?: sprintf('Newly built index %s was deleted', $newIndexName)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the old index after the alias has been switched
|
||||||
|
if ($oldIndexName) {
|
||||||
|
$oldIndex = new Index($esIndex->getClient(), $oldIndexName);
|
||||||
|
try {
|
||||||
|
$oldIndex->delete();
|
||||||
|
} catch (ExceptionInterface $deleteOldIndexException) {
|
||||||
|
throw new \RuntimeException(
|
||||||
|
sprintf(
|
||||||
|
'Failed to delete old index %s with message: %s',
|
||||||
|
$oldIndexName,
|
||||||
|
$deleteOldIndexException->getMessage()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns array of indexes which are mapped to given alias
|
||||||
|
*
|
||||||
|
* @param Index $esIndex ES Index
|
||||||
|
* @param string $aliasName Alias name
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getAliasedIndexes(Index $esIndex, $aliasName)
|
||||||
|
{
|
||||||
|
$aliasesInfo = $esIndex->getClient()->request('_aliases', 'GET')->getData();
|
||||||
|
$aliasedIndexes = array();
|
||||||
|
|
||||||
|
foreach ($aliasesInfo as $indexName => $indexInfo) {
|
||||||
|
$aliases = array_keys($indexInfo['aliases']);
|
||||||
|
if (in_array($aliasName, $aliases)) {
|
||||||
|
$aliasedIndexes[] = $indexName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $aliasedIndexes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
<parameters>
|
<parameters>
|
||||||
<parameter key="fos_elastica.client.class">FOS\ElasticaBundle\Client</parameter>
|
<parameter key="fos_elastica.client.class">FOS\ElasticaBundle\Client</parameter>
|
||||||
<parameter key="fos_elastica.index.class">Elastica\Index</parameter>
|
<parameter key="fos_elastica.index.class">FOS\ElasticaBundle\DynamicIndex</parameter>
|
||||||
<parameter key="fos_elastica.type.class">Elastica\Type</parameter>
|
<parameter key="fos_elastica.type.class">Elastica\Type</parameter>
|
||||||
<parameter key="fos_elastica.logger.class">FOS\ElasticaBundle\Logger\ElasticaLogger</parameter>
|
<parameter key="fos_elastica.logger.class">FOS\ElasticaBundle\Logger\ElasticaLogger</parameter>
|
||||||
<parameter key="fos_elastica.data_collector.class">FOS\ElasticaBundle\DataCollector\ElasticaDataCollector</parameter>
|
<parameter key="fos_elastica.data_collector.class">FOS\ElasticaBundle\DataCollector\ElasticaDataCollector</parameter>
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<argument type="service" id="doctrine_mongodb" />
|
<argument type="service" id="doctrine_mongodb" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service id="fos_elastica.listener.prototype.mongodb" class="FOS\ElasticaBundle\Doctrine\MongoDB\Listener" public="false" abstract="true">
|
<service id="fos_elastica.listener.prototype.mongodb" class="FOS\ElasticaBundle\Doctrine\Listener" public="false">
|
||||||
<argument /> <!-- object persister -->
|
<argument /> <!-- object persister -->
|
||||||
<argument /> <!-- model -->
|
<argument /> <!-- model -->
|
||||||
<argument type="collection" /> <!-- events -->
|
<argument type="collection" /> <!-- events -->
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<argument type="service" id="doctrine" />
|
<argument type="service" id="doctrine" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service id="fos_elastica.listener.prototype.orm" class="FOS\ElasticaBundle\Doctrine\ORM\Listener" public="false" abstract="true">
|
<service id="fos_elastica.listener.prototype.orm" class="FOS\ElasticaBundle\Doctrine\Listener" public="false">
|
||||||
<argument /> <!-- object persister -->
|
<argument /> <!-- object persister -->
|
||||||
<argument /> <!-- model -->
|
<argument /> <!-- model -->
|
||||||
<argument type="collection" /> <!-- events -->
|
<argument type="collection" /> <!-- events -->
|
||||||
|
|
|
@ -3,9 +3,11 @@
|
||||||
namespace FOS\ElasticaBundle\Tests\Doctrine;
|
namespace FOS\ElasticaBundle\Tests\Doctrine;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* See concrete MongoDB/ORM instances of this abstract test
|
||||||
|
*
|
||||||
* @author Richard Miller <info@limethinking.co.uk>
|
* @author Richard Miller <info@limethinking.co.uk>
|
||||||
*/
|
*/
|
||||||
abstract class AbstractListenerTest extends \PHPUnit_Framework_TestCase
|
abstract class ListenerTest extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
public function testObjectInsertedOnPersist()
|
public function testObjectInsertedOnPersist()
|
||||||
{
|
{
|
||||||
|
@ -14,12 +16,16 @@ abstract class AbstractListenerTest extends \PHPUnit_Framework_TestCase
|
||||||
$entity = new Listener\Entity(1);
|
$entity = new Listener\Entity(1);
|
||||||
$eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager());
|
$eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager());
|
||||||
|
|
||||||
$persister->expects($this->once())
|
|
||||||
->method('insertOne')
|
|
||||||
->with($entity);
|
|
||||||
|
|
||||||
$listener = $this->createListener($persister, get_class($entity), array());
|
$listener = $this->createListener($persister, get_class($entity), array());
|
||||||
$listener->postPersist($eventArgs);
|
$listener->postPersist($eventArgs);
|
||||||
|
|
||||||
|
$this->assertEquals($entity, current($listener->scheduledForInsertion));
|
||||||
|
|
||||||
|
$persister->expects($this->once())
|
||||||
|
->method('insertMany')
|
||||||
|
->with($listener->scheduledForInsertion);
|
||||||
|
|
||||||
|
$listener->postFlush($eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,12 +38,18 @@ abstract class AbstractListenerTest extends \PHPUnit_Framework_TestCase
|
||||||
$entity = new Listener\Entity(1, false);
|
$entity = new Listener\Entity(1, false);
|
||||||
$eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager());
|
$eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager());
|
||||||
|
|
||||||
$persister->expects($this->never())
|
|
||||||
->method('insertOne');
|
|
||||||
|
|
||||||
$listener = $this->createListener($persister, get_class($entity), array());
|
$listener = $this->createListener($persister, get_class($entity), array());
|
||||||
$listener->setIsIndexableCallback($isIndexableCallback);
|
$listener->setIsIndexableCallback($isIndexableCallback);
|
||||||
$listener->postPersist($eventArgs);
|
$listener->postPersist($eventArgs);
|
||||||
|
|
||||||
|
$this->assertEmpty($listener->scheduledForInsertion);
|
||||||
|
|
||||||
|
$persister->expects($this->never())
|
||||||
|
->method('insertOne');
|
||||||
|
$persister->expects($this->never())
|
||||||
|
->method('insertMany');
|
||||||
|
|
||||||
|
$listener->postFlush($eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testObjectReplacedOnUpdate()
|
public function testObjectReplacedOnUpdate()
|
||||||
|
@ -47,15 +59,18 @@ abstract class AbstractListenerTest extends \PHPUnit_Framework_TestCase
|
||||||
$entity = new Listener\Entity(1);
|
$entity = new Listener\Entity(1);
|
||||||
$eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager());
|
$eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager());
|
||||||
|
|
||||||
$persister->expects($this->once())
|
$listener = $this->createListener($persister, get_class($entity), array());
|
||||||
->method('replaceOne')
|
$listener->postUpdate($eventArgs);
|
||||||
->with($entity);
|
|
||||||
|
|
||||||
|
$this->assertEquals($entity, current($listener->scheduledForUpdate));
|
||||||
|
|
||||||
|
$persister->expects($this->once())
|
||||||
|
->method('replaceMany')
|
||||||
|
->with(array($entity));
|
||||||
$persister->expects($this->never())
|
$persister->expects($this->never())
|
||||||
->method('deleteById');
|
->method('deleteById');
|
||||||
|
|
||||||
$listener = $this->createListener($persister, get_class($entity), array());
|
$listener->postFlush($eventArgs);
|
||||||
$listener->postUpdate($eventArgs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -80,16 +95,20 @@ abstract class AbstractListenerTest extends \PHPUnit_Framework_TestCase
|
||||||
->with($entity, 'id')
|
->with($entity, 'id')
|
||||||
->will($this->returnValue($entity->getId()));
|
->will($this->returnValue($entity->getId()));
|
||||||
|
|
||||||
$persister->expects($this->never())
|
|
||||||
->method('replaceOne');
|
|
||||||
|
|
||||||
$persister->expects($this->once())
|
|
||||||
->method('deleteById')
|
|
||||||
->with($entity->getId());
|
|
||||||
|
|
||||||
$listener = $this->createListener($persister, get_class($entity), array());
|
$listener = $this->createListener($persister, get_class($entity), array());
|
||||||
$listener->setIsIndexableCallback($isIndexableCallback);
|
$listener->setIsIndexableCallback($isIndexableCallback);
|
||||||
$listener->postUpdate($eventArgs);
|
$listener->postUpdate($eventArgs);
|
||||||
|
|
||||||
|
$this->assertEmpty($listener->scheduledForUpdate);
|
||||||
|
$this->assertEquals($entity, current($listener->scheduledForDeletion));
|
||||||
|
|
||||||
|
$persister->expects($this->never())
|
||||||
|
->method('replaceOne');
|
||||||
|
$persister->expects($this->once())
|
||||||
|
->method('deleteMany')
|
||||||
|
->with(array($entity));
|
||||||
|
|
||||||
|
$listener->postFlush($eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testObjectDeletedOnRemove()
|
public function testObjectDeletedOnRemove()
|
||||||
|
@ -111,13 +130,16 @@ abstract class AbstractListenerTest extends \PHPUnit_Framework_TestCase
|
||||||
->with($entity, 'id')
|
->with($entity, 'id')
|
||||||
->will($this->returnValue($entity->getId()));
|
->will($this->returnValue($entity->getId()));
|
||||||
|
|
||||||
$persister->expects($this->once())
|
|
||||||
->method('deleteById')
|
|
||||||
->with($entity->getId());
|
|
||||||
|
|
||||||
$listener = $this->createListener($persister, get_class($entity), array());
|
$listener = $this->createListener($persister, get_class($entity), array());
|
||||||
$listener->preRemove($eventArgs);
|
$listener->preRemove($eventArgs);
|
||||||
$listener->postRemove($eventArgs);
|
|
||||||
|
$this->assertEquals($entity, current($listener->scheduledForDeletion));
|
||||||
|
|
||||||
|
$persister->expects($this->once())
|
||||||
|
->method('deleteMany')
|
||||||
|
->with(array($entity));
|
||||||
|
|
||||||
|
$listener->postFlush($eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testObjectWithNonStandardIdentifierDeletedOnRemove()
|
public function testObjectWithNonStandardIdentifierDeletedOnRemove()
|
||||||
|
@ -139,13 +161,16 @@ abstract class AbstractListenerTest extends \PHPUnit_Framework_TestCase
|
||||||
->with($entity, 'identifier')
|
->with($entity, 'identifier')
|
||||||
->will($this->returnValue($entity->getId()));
|
->will($this->returnValue($entity->getId()));
|
||||||
|
|
||||||
$persister->expects($this->once())
|
|
||||||
->method('deleteById')
|
|
||||||
->with($entity->getId());
|
|
||||||
|
|
||||||
$listener = $this->createListener($persister, get_class($entity), array(), 'identifier');
|
$listener = $this->createListener($persister, get_class($entity), array(), 'identifier');
|
||||||
$listener->preRemove($eventArgs);
|
$listener->preRemove($eventArgs);
|
||||||
$listener->postRemove($eventArgs);
|
|
||||||
|
$this->assertEquals($entity, current($listener->scheduledForDeletion));
|
||||||
|
|
||||||
|
$persister->expects($this->once())
|
||||||
|
->method('deleteMany')
|
||||||
|
->with(array($entity));
|
||||||
|
|
||||||
|
$listener->postFlush($eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
namespace FOS\ElasticaBundle\Tests\Doctrine\MongoDB;
|
namespace FOS\ElasticaBundle\Tests\Doctrine\MongoDB;
|
||||||
|
|
||||||
use FOS\ElasticaBundle\Tests\Doctrine\AbstractListenerTest;
|
use FOS\ElasticaBundle\Tests\Doctrine\ListenerTest as BaseListenerTest;
|
||||||
|
|
||||||
class ListenerTest extends AbstractListenerTest
|
class ListenerTest extends BaseListenerTest
|
||||||
{
|
{
|
||||||
public function setUp()
|
public function setUp()
|
||||||
{
|
{
|
||||||
|
@ -25,7 +25,7 @@ class ListenerTest extends AbstractListenerTest
|
||||||
|
|
||||||
protected function getListenerClass()
|
protected function getListenerClass()
|
||||||
{
|
{
|
||||||
return 'FOS\ElasticaBundle\Doctrine\MongoDB\Listener';
|
return 'FOS\ElasticaBundle\Doctrine\Listener';
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getObjectManagerClass()
|
protected function getObjectManagerClass()
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
namespace FOS\ElasticaBundle\Tests\Doctrine\ORM;
|
namespace FOS\ElasticaBundle\Tests\Doctrine\ORM;
|
||||||
|
|
||||||
use FOS\ElasticaBundle\Tests\Doctrine\AbstractListenerTest;
|
use FOS\ElasticaBundle\Tests\Doctrine\ListenerTest as BaseListenerTest;
|
||||||
|
|
||||||
class ListenerTest extends AbstractListenerTest
|
class ListenerTest extends BaseListenerTest
|
||||||
{
|
{
|
||||||
public function setUp()
|
public function setUp()
|
||||||
{
|
{
|
||||||
|
@ -25,7 +25,7 @@ class ListenerTest extends AbstractListenerTest
|
||||||
|
|
||||||
protected function getListenerClass()
|
protected function getListenerClass()
|
||||||
{
|
{
|
||||||
return 'FOS\ElasticaBundle\Doctrine\ORM\Listener';
|
return 'FOS\ElasticaBundle\Doctrine\Listener';
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getObjectManagerClass()
|
protected function getObjectManagerClass()
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
namespace FOS\ElasticaBundle\Tests\Resetter;
|
namespace FOS\ElasticaBundle\Tests\Resetter;
|
||||||
|
|
||||||
|
use Elastica\Exception\ResponseException;
|
||||||
|
use Elastica\Request;
|
||||||
|
use Elastica\Response;
|
||||||
use FOS\ElasticaBundle\Resetter;
|
use FOS\ElasticaBundle\Resetter;
|
||||||
use Elastica\Type\Mapping;
|
use Elastica\Type\Mapping;
|
||||||
|
|
||||||
|
@ -130,6 +133,32 @@ class ResetterTest extends \PHPUnit_Framework_TestCase
|
||||||
$resetter->resetIndexType('foo', 'c');
|
$resetter->resetIndexType('foo', 'c');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testResetIndexTypeIgnoreTypeMissingException()
|
||||||
|
{
|
||||||
|
$type = $this->getMockElasticaType();
|
||||||
|
|
||||||
|
$this->indexConfigsByName['foo']['index']->expects($this->once())
|
||||||
|
->method('getType')
|
||||||
|
->with('a')
|
||||||
|
->will($this->returnValue($type));
|
||||||
|
|
||||||
|
$type->expects($this->once())
|
||||||
|
->method('delete')
|
||||||
|
->will($this->throwException(new ResponseException(
|
||||||
|
new Request(''),
|
||||||
|
new Response(array('error' => 'TypeMissingException[[de_20131022] type[bla] missing]', 'status' => 404)))
|
||||||
|
));
|
||||||
|
|
||||||
|
$mapping = Mapping::create($this->indexConfigsByName['foo']['config']['mappings']['a']['properties']);
|
||||||
|
$mapping->setParam('dynamic_templates', $this->indexConfigsByName['foo']['config']['mappings']['a']['dynamic_templates']);
|
||||||
|
$type->expects($this->once())
|
||||||
|
->method('setMapping')
|
||||||
|
->with($mapping);
|
||||||
|
|
||||||
|
$resetter = new Resetter($this->indexConfigsByName);
|
||||||
|
$resetter->resetIndexType('foo', 'a');
|
||||||
|
}
|
||||||
|
|
||||||
public function testIndexMappingForParent()
|
public function testIndexMappingForParent()
|
||||||
{
|
{
|
||||||
$type = $this->getMockElasticaType();
|
$type = $this->getMockElasticaType();
|
||||||
|
|
|
@ -12,11 +12,11 @@
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.3.2",
|
"php": ">=5.3.2",
|
||||||
"symfony/framework-bundle": "~2.1",
|
"symfony/framework-bundle": "~2.3",
|
||||||
"symfony/console": "~2.1",
|
"symfony/console": "~2.1",
|
||||||
"symfony/form": "~2.1",
|
"symfony/form": "~2.1",
|
||||||
"symfony/property-access": "~2.2",
|
"symfony/property-access": "~2.2",
|
||||||
"ruflin/elastica": "~0.20",
|
"ruflin/elastica": ">=0.20, <1.1-dev",
|
||||||
"psr/log": "~1.0"
|
"psr/log": "~1.0"
|
||||||
},
|
},
|
||||||
"require-dev":{
|
"require-dev":{
|
||||||
|
|
Loading…
Reference in a new issue