diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php
index ce1c982..f32f295 100644
--- a/DependencyInjection/Configuration.php
+++ b/DependencyInjection/Configuration.php
@@ -187,9 +187,23 @@ class Configuration implements ConfigurationInterface
return $v;
})
->end()
+ ->beforeNormalization()
+ ->ifTrue(function ($v) {
+ return isset($v['persistence']) &&
+ isset($v['persistence']['listener']) &&
+ isset($v['persistence']['listener']['is_indexable_callback']);
+ })
+ ->then(function ($v) {
+ $v['indexable_callback'] = $v['persistence']['listener']['is_indexable_callback'];
+ unset($v['persistence']['listener']['is_indexable_callback']);
+
+ return $v;
+ })
+ ->end()
->children()
->scalarNode('index_analyzer')->end()
->scalarNode('search_analyzer')->end()
+ ->scalarNode('indexable_callback')->end()
->append($this->getPersistenceNode())
->append($this->getSerializerNode())
->end()
@@ -230,7 +244,7 @@ class Configuration implements ConfigurationInterface
unset($v[$prop]);
}
}
-
+
return $v;
})
->end()
@@ -674,7 +688,6 @@ class Configuration implements ConfigurationInterface
->treatTrueLike('fos_elastica.logger')
->end()
->scalarNode('service')->end()
- ->variableNode('is_indexable_callback')->defaultNull()->end()
->end()
->end()
->arrayNode('finder')
diff --git a/DependencyInjection/FOSElasticaExtension.php b/DependencyInjection/FOSElasticaExtension.php
index 1529544..9e50c0b 100644
--- a/DependencyInjection/FOSElasticaExtension.php
+++ b/DependencyInjection/FOSElasticaExtension.php
@@ -186,8 +186,11 @@ class FOSElasticaExtension extends Extension
*/
protected function loadTypes(array $types, ContainerBuilder $container, $indexName, $indexId, array $typePrototypeConfig)
{
+ $indexableCallbacks = array();
+
foreach ($types as $name => $type) {
$type = self::deepArrayUnion($typePrototypeConfig, $type);
+ $typeName = sprintf('%s/%s', $indexName, $name);
$typeId = sprintf('%s.%s', $indexId, $name);
$typeDefArgs = array($name);
$typeDef = new Definition('%fos_elastica.type.class%', $typeDefArgs);
@@ -240,7 +243,6 @@ class FOSElasticaExtension extends Extension
}
if (isset($type['_parent'])) {
$this->indexConfigs[$indexName]['config']['properties'][$name]['_parent'] = array('type' => $type['_parent']['type']);
- $typeName = sprintf('%s/%s', $indexName, $name);
$this->typeFields[$typeName]['_parent'] = $type['_parent'];
}
if (isset($type['persistence'])) {
@@ -252,6 +254,9 @@ class FOSElasticaExtension extends Extension
if (isset($type['search_analyzer'])) {
$this->indexConfigs[$indexName]['config']['properties'][$name]['search_analyzer'] = $type['search_analyzer'];
}
+ if (isset($type['indexable_callback'])) {
+ $indexableCallbacks[$typeName] = $type['indexable_callback'];
+ }
if (isset($type['index'])) {
$this->indexConfigs[$indexName]['config']['properties'][$name]['index'] = $type['index'];
}
@@ -271,6 +276,9 @@ class FOSElasticaExtension extends Extension
}
}
}
+
+ $indexable = $container->getDefinition('fos_elastica.indexable');
+ $indexable->replaceArgument(0, $indexableCallbacks);
}
/**
@@ -431,8 +439,7 @@ class FOSElasticaExtension extends Extension
$listenerId = sprintf('fos_elastica.listener.%s.%s', $indexName, $typeName);
$listenerDef = new DefinitionDecorator($abstractListenerId);
$listenerDef->replaceArgument(0, new Reference($objectPersisterId));
- $listenerDef->replaceArgument(1, $typeConfig['model']);
- $listenerDef->replaceArgument(2, $this->getDoctrineEvents($typeConfig));
+ $listenerDef->replaceArgument(1, $this->getDoctrineEvents($typeConfig));
$listenerDef->replaceArgument(3, $typeConfig['identifier']);
if ($typeConfig['listener']['logger']) {
$listenerDef->replaceArgument(4, new Reference($typeConfig['listener']['logger']));
@@ -442,18 +449,7 @@ class FOSElasticaExtension extends Extension
case 'orm': $listenerDef->addTag('doctrine.event_subscriber'); break;
case 'mongodb': $listenerDef->addTag('doctrine_mongodb.odm.event_subscriber'); break;
}
- if (isset($typeConfig['listener']['is_indexable_callback'])) {
- $callback = $typeConfig['listener']['is_indexable_callback'];
- if (is_array($callback)) {
- list($class) = $callback + array(null);
- if (is_string($class) && !class_exists($class)) {
- $callback[0] = new Reference($class);
- }
- }
-
- $listenerDef->addMethodCall('setIsIndexableCallback', array($callback));
- }
$container->setDefinition($listenerId, $listenerDef);
return $listenerId;
diff --git a/Doctrine/Listener.php b/Doctrine/Listener.php
index ff9fc60..4a01aa1 100644
--- a/Doctrine/Listener.php
+++ b/Doctrine/Listener.php
@@ -2,15 +2,13 @@
namespace FOS\ElasticaBundle\Doctrine;
-use Psr\Log\LoggerInterface;
use Doctrine\Common\EventArgs;
use Doctrine\Common\EventSubscriber;
use FOS\ElasticaBundle\Persister\ObjectPersisterInterface;
use FOS\ElasticaBundle\Persister\ObjectPersister;
-use Symfony\Component\ExpressionLanguage\Expression;
-use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
-use Symfony\Component\ExpressionLanguage\SyntaxError;
+use FOS\ElasticaBundle\Provider\IndexableInterface;
use Symfony\Component\PropertyAccess\PropertyAccess;
+use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
/**
* Automatically update ElasticSearch based on changes to the Doctrine source
@@ -25,13 +23,6 @@ class Listener implements EventSubscriber
*/
protected $objectPersister;
- /**
- * Class of the domain model
- *
- * @var string
- */
- protected $objectClass;
-
/**
* List of subscribed events
*
@@ -46,13 +37,6 @@ class Listener implements EventSubscriber
*/
protected $esIdentifierField;
- /**
- * Callback for determining if an object should be indexed
- *
- * @var mixed
- */
- protected $isIndexableCallback;
-
/**
* Objects scheduled for insertion and replacement
*/
@@ -64,13 +48,6 @@ class Listener implements EventSubscriber
*/
public $scheduledForDeletion = array();
- /**
- * An instance of ExpressionLanguage
- *
- * @var ExpressionLanguage
- */
- protected $expressionLanguage;
-
/**
* PropertyAccessor instance
*
@@ -78,26 +55,36 @@ class Listener implements EventSubscriber
*/
protected $propertyAccessor;
+ /**
+ * @var \FOS\ElasticaBundle\Provider\IndexableInterface
+ */
+ private $indexable;
+
/**
* Constructor.
*
* @param ObjectPersisterInterface $objectPersister
- * @param string $objectClass
- * @param array $events
- * @param string $esIdentifierField
+ * @param array $events
+ * @param IndexableInterface $indexable
+ * @param string $esIdentifierField
+ * @param null $logger
*/
- public function __construct(ObjectPersisterInterface $objectPersister, $objectClass, array $events, $esIdentifierField = 'id', $logger = null)
- {
- $this->objectPersister = $objectPersister;
- $this->objectClass = $objectClass;
- $this->events = $events;
- $this->esIdentifierField = $esIdentifierField;
+ public function __construct(
+ ObjectPersisterInterface $objectPersister,
+ array $events,
+ IndexableInterface $indexable,
+ $esIdentifierField = 'id',
+ $logger = null
+ ) {
+ $this->esIdentifierField = $esIdentifierField;
+ $this->events = $events;
+ $this->indexable = $indexable;
+ $this->objectPersister = $objectPersister;
+ $this->propertyAccessor = PropertyAccess::createPropertyAccessor();
if ($logger) {
$this->objectPersister->setLogger($logger);
}
-
- $this->propertyAccessor = PropertyAccess::createPropertyAccessor();
}
/**
@@ -108,82 +95,6 @@ class Listener implements EventSubscriber
return $this->events;
}
- /**
- * Set the callback for determining object index eligibility.
- *
- * If callback is a string, it must be public method on the object class
- * that expects no arguments and returns a boolean. Otherwise, the callback
- * should expect the object for consideration as its only argument and
- * return a boolean.
- *
- * @param callback $callback
- * @throws \RuntimeException if the callback is not callable
- */
- public function setIsIndexableCallback($callback)
- {
- if (is_string($callback)) {
- if (!is_callable(array($this->objectClass, $callback))) {
- if (false !== ($expression = $this->getExpressionLanguage())) {
- $callback = new Expression($callback);
- try {
- $expression->compile($callback, array($this->getExpressionVar()));
- } catch (SyntaxError $e) {
- throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable or a valid expression.', $this->objectClass, $callback), 0, $e);
- }
- } else {
- throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable.', $this->objectClass, $callback));
- }
- }
- } elseif (!is_callable($callback)) {
- if (is_array($callback)) {
- list($class, $method) = $callback + array(null, null);
- if (is_object($class)) {
- $class = get_class($class);
- }
-
- if ($class && $method) {
- throw new \RuntimeException(sprintf('Indexable callback %s::%s() is not callable.', $class, $method));
- }
- }
- throw new \RuntimeException('Indexable callback is not callable.');
- }
-
- $this->isIndexableCallback = $callback;
- }
-
- /**
- * Return whether the object is indexable with respect to the callback.
- *
- * @param object $object
- * @return boolean
- */
- protected function isObjectIndexable($object)
- {
- if (!$this->isIndexableCallback) {
- return true;
- }
-
- if ($this->isIndexableCallback instanceof Expression) {
- return $this->getExpressionLanguage()->evaluate($this->isIndexableCallback, array($this->getExpressionVar($object) => $object));
- }
-
- return is_string($this->isIndexableCallback)
- ? call_user_func(array($object, $this->isIndexableCallback))
- : call_user_func($this->isIndexableCallback, $object);
- }
-
- /**
- * @param mixed $object
- * @return string
- */
- private function getExpressionVar($object = null)
- {
- $class = $object ?: $this->objectClass;
- $ref = new \ReflectionClass($class);
-
- return strtolower($ref->getShortName());
- }
-
/**
* Provides unified method for retrieving a doctrine object from an EventArgs instance
*
@@ -204,27 +115,11 @@ class Listener implements EventSubscriber
throw new \RuntimeException('Unable to retrieve object from EventArgs.');
}
- /**
- * @return bool|ExpressionLanguage
- */
- private function getExpressionLanguage()
- {
- if (null === $this->expressionLanguage) {
- if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
- return false;
- }
-
- $this->expressionLanguage = new ExpressionLanguage();
- }
-
- return $this->expressionLanguage;
- }
-
public function postPersist(EventArgs $eventArgs)
{
$entity = $this->getDoctrineObject($eventArgs);
- if ($entity instanceof $this->objectClass && $this->isObjectIndexable($entity)) {
+ if ($this->objectPersister->handlesObject($entity) && $this->isObjectIndexable($entity)) {
$this->scheduledForInsertion[] = $entity;
}
}
@@ -233,7 +128,7 @@ class Listener implements EventSubscriber
{
$entity = $this->getDoctrineObject($eventArgs);
- if ($entity instanceof $this->objectClass) {
+ if ($this->objectPersister->handlesObject($entity)) {
if ($this->isObjectIndexable($entity)) {
$this->scheduledForUpdate[] = $entity;
} else {
@@ -251,7 +146,7 @@ class Listener implements EventSubscriber
{
$entity = $this->getDoctrineObject($eventArgs);
- if ($entity instanceof $this->objectClass) {
+ if ($this->objectPersister->handlesObject($entity)) {
$this->scheduleForDeletion($entity);
}
}
@@ -305,4 +200,19 @@ class Listener implements EventSubscriber
$this->scheduledForDeletion[] = $identifierValue;
}
}
+
+ /**
+ * Checks if the object is indexable or not.
+ *
+ * @param object $object
+ * @return bool
+ */
+ private function isObjectIndexable($object)
+ {
+ return $this->indexable->isObjectIndexable(
+ $this->objectPersister->getType()->getIndex()->getName(),
+ $this->objectPersister->getType()->getName(),
+ $object
+ );
+ }
}
diff --git a/Persister/ObjectPersister.php b/Persister/ObjectPersister.php
index c279ec7..2b6a8af 100644
--- a/Persister/ObjectPersister.php
+++ b/Persister/ObjectPersister.php
@@ -31,6 +31,27 @@ class ObjectPersister implements ObjectPersisterInterface
$this->fields = $fields;
}
+ /**
+ * @internal Temporary method that will be removed.
+ *
+ * @return Type
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ * If the ObjectPersister handles a given object.
+ *
+ * @param object $object
+ * @return bool
+ */
+ public function handlesObject($object)
+ {
+ return $object instanceof $this->objectClass;
+ }
+
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
diff --git a/Provider/Indexable.php b/Provider/Indexable.php
new file mode 100644
index 0000000..b388c58
--- /dev/null
+++ b/Provider/Indexable.php
@@ -0,0 +1,174 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace FOS\ElasticaBundle\Provider;
+
+use Symfony\Component\ExpressionLanguage\Expression;
+use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
+use Symfony\Component\ExpressionLanguage\SyntaxError;
+use Symfony\Component\PropertyAccess\PropertyAccess;
+use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
+
+class Indexable implements IndexableInterface
+{
+ /**
+ * An array of raw configured callbacks for all types.
+ *
+ * @var array
+ */
+ private $callbacks = array();
+
+ /**
+ * An instance of ExpressionLanguage
+ *
+ * @var ExpressionLanguage
+ */
+ private $expressionLanguage;
+
+ /**
+ * An array of initialised callbacks.
+ *
+ * @var array
+ */
+ private $initialisedCallbacks = array();
+
+ /**
+ * PropertyAccessor instance
+ *
+ * @var PropertyAccessorInterface
+ */
+ private $propertyAccessor;
+
+ /**
+ * @param array $callbacks
+ */
+ public function __construct(array $callbacks)
+ {
+ $this->callbacks = $callbacks;
+ $this->propertyAccessor = PropertyAccess::createPropertyAccessor();
+ }
+
+ /**
+ * Return whether the object is indexable with respect to the callback.
+ *
+ * @param string $indexName
+ * @param string $typeName
+ * @param mixed $object
+ * @return bool
+ */
+ public function isObjectIndexable($indexName, $typeName, $object)
+ {
+ $type = sprintf('%s/%s', $indexName, $typeName);
+ $callback = $this->getCallback($type, $object);
+ if (!$callback) {
+ return true;
+ }
+
+ if ($callback instanceof Expression) {
+ return $this->getExpressionLanguage()->evaluate($callback, array(
+ 'object' => $object,
+ $this->getExpressionVar($object) => $object
+ ));
+ }
+
+ return is_string($callback)
+ ? call_user_func(array($object, $callback))
+ : call_user_func($callback, $object);
+ }
+
+ /**
+ * Builds and initialises a callback.
+ *
+ * @param string $type
+ * @param object $object
+ * @return mixed
+ */
+ private function buildCallback($type, $object)
+ {
+ if (!array_key_exists($type, $this->callbacks)) {
+ throw new \InvalidArgumentException(sprintf('Callback for type "%s" is not configured', $type));
+ }
+
+ $callback = $this->callbacks[$type];
+
+ if (is_callable($callback) or is_callable(array($object, $callback))) {
+ return $callback;
+ }
+
+ if (is_array($callback)) {
+ list($class, $method) = $callback + array(null, null);
+ if (is_object($class)) {
+ $class = get_class($class);
+ }
+
+ if ($class && $method) {
+ throw new \InvalidArgumentException(sprintf('Callback for type "%s", "%s::%s()", is not callable.', $type, $class, $method));
+ }
+ }
+
+ if (is_string($callback) && $expression = $this->getExpressionLanguage()) {
+ $callback = new Expression($callback);
+
+ try {
+ $expression->compile($callback, array('object', $this->getExpressionVar($object)));
+
+ return $callback;
+ } catch (SyntaxError $e) {
+ throw new \InvalidArgumentException(sprintf('Callback for type "%s" is an invalid expression', $type), $e->getCode(), $e);
+ }
+ }
+
+ throw new \InvalidArgumentException(sprintf('Callback for type "%s" is not a valid callback.', $type));
+ }
+
+ /**
+ * Retreives a cached callback, or creates a new callback if one is not found.
+ *
+ * @param string $type
+ * @param object $object
+ * @return mixed
+ */
+ private function getCallback($type, $object)
+ {
+ if (!array_key_exists($type, $this->initialisedCallbacks)) {
+ $this->initialisedCallbacks[$type] = $this->buildCallback($type, $object);
+ }
+
+ return $this->initialisedCallbacks[$type];
+ }
+
+ /**
+ * @return bool|ExpressionLanguage
+ */
+ private function getExpressionLanguage()
+ {
+ if (null === $this->expressionLanguage) {
+ if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
+ return false;
+ }
+
+ $this->expressionLanguage = new ExpressionLanguage();
+ }
+
+ return $this->expressionLanguage;
+ }
+
+ /**
+ * @param mixed $object
+ * @return string
+ */
+ private function getExpressionVar($object = null)
+ {
+ $ref = new \ReflectionClass($object);
+
+ return strtolower($ref->getShortName());
+ }
+}
diff --git a/Provider/IndexableInterface.php b/Provider/IndexableInterface.php
new file mode 100644
index 0000000..4871b58
--- /dev/null
+++ b/Provider/IndexableInterface.php
@@ -0,0 +1,25 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace FOS\ElasticaBundle\Provider;
+
+interface IndexableInterface
+{
+ /**
+ * Checks if an object passed should be indexable or not.
+ *
+ * @param string $indexName
+ * @param string $typeName
+ * @param mixed $object
+ * @return bool
+ */
+ public function isObjectIndexable($indexName, $typeName, $object);
+}
diff --git a/Resources/config/config.xml b/Resources/config/config.xml
index 7687250..f4b2606 100644
--- a/Resources/config/config.xml
+++ b/Resources/config/config.xml
@@ -9,6 +9,7 @@
FOS\ElasticaBundle\DynamicIndex
Elastica\Type
FOS\ElasticaBundle\IndexManager
+ FOS\ElasticaBundle\Provider\Indexable
FOS\ElasticaBundle\Resetter
FOS\ElasticaBundle\Finder\TransformedFinder
FOS\ElasticaBundle\Logger\ElasticaLogger
@@ -44,6 +45,10 @@
+
+
+
+
diff --git a/Resources/config/mongodb.xml b/Resources/config/mongodb.xml
index 0af7aa1..e575e5d 100644
--- a/Resources/config/mongodb.xml
+++ b/Resources/config/mongodb.xml
@@ -15,9 +15,10 @@
-
+
+
diff --git a/Resources/config/orm.xml b/Resources/config/orm.xml
index 5bd16e5..43d1670 100644
--- a/Resources/config/orm.xml
+++ b/Resources/config/orm.xml
@@ -15,10 +15,10 @@
-
-
-
+
+
+
diff --git a/Tests/Doctrine/AbstractListenerTest.php b/Tests/Doctrine/AbstractListenerTest.php
index ee657f1..de5ba0c 100644
--- a/Tests/Doctrine/AbstractListenerTest.php
+++ b/Tests/Doctrine/AbstractListenerTest.php
@@ -11,12 +11,12 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase
{
public function testObjectInsertedOnPersist()
{
- $persister = $this->getMockPersister();
-
$entity = new Listener\Entity(1);
+ $persister = $this->getMockPersister($entity, 'index', 'type');
$eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager());
+ $indexable = $this->getMockIndexable('index', 'type', $entity, true);
- $listener = $this->createListener($persister, get_class($entity), array());
+ $listener = $this->createListener($persister, array(), $indexable);
$listener->postPersist($eventArgs);
$this->assertEquals($entity, current($listener->scheduledForInsertion));
@@ -28,18 +28,14 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase
$listener->postFlush($eventArgs);
}
- /**
- * @dataProvider provideIsIndexableCallbacks
- */
- public function testNonIndexableObjectNotInsertedOnPersist($isIndexableCallback)
+ public function testNonIndexableObjectNotInsertedOnPersist()
{
- $persister = $this->getMockPersister();
-
- $entity = new Listener\Entity(1, false);
+ $entity = new Listener\Entity(1);
+ $persister = $this->getMockPersister($entity, 'index', 'type');
$eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager());
+ $indexable = $this->getMockIndexable('index', 'type', $entity, false);
- $listener = $this->createListener($persister, get_class($entity), array());
- $listener->setIsIndexableCallback($isIndexableCallback);
+ $listener = $this->createListener($persister, array(), $indexable);
$listener->postPersist($eventArgs);
$this->assertEmpty($listener->scheduledForInsertion);
@@ -54,12 +50,12 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase
public function testObjectReplacedOnUpdate()
{
- $persister = $this->getMockPersister();
-
$entity = new Listener\Entity(1);
+ $persister = $this->getMockPersister($entity, 'index', 'type');
$eventArgs = $this->createLifecycleEventArgs($entity, $this->getMockObjectManager());
+ $indexable = $this->getMockIndexable('index', 'type', $entity, true);
- $listener = $this->createListener($persister, get_class($entity), array());
+ $listener = $this->createListener($persister, array(), $indexable);
$listener->postUpdate($eventArgs);
$this->assertEquals($entity, current($listener->scheduledForUpdate));
@@ -73,17 +69,15 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase
$listener->postFlush($eventArgs);
}
- /**
- * @dataProvider provideIsIndexableCallbacks
- */
- public function testNonIndexableObjectRemovedOnUpdate($isIndexableCallback)
+ public function testNonIndexableObjectRemovedOnUpdate()
{
$classMetadata = $this->getMockClassMetadata();
$objectManager = $this->getMockObjectManager();
- $persister = $this->getMockPersister();
- $entity = new Listener\Entity(1, false);
+ $entity = new Listener\Entity(1);
+ $persister = $this->getMockPersister($entity, 'index', 'type');
$eventArgs = $this->createLifecycleEventArgs($entity, $objectManager);
+ $indexable = $this->getMockIndexable('index', 'type', $entity, false);
$objectManager->expects($this->any())
->method('getClassMetadata')
@@ -95,8 +89,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase
->with($entity, 'id')
->will($this->returnValue($entity->getId()));
- $listener = $this->createListener($persister, get_class($entity), array());
- $listener->setIsIndexableCallback($isIndexableCallback);
+ $listener = $this->createListener($persister, array(), $indexable);
$listener->postUpdate($eventArgs);
$this->assertEmpty($listener->scheduledForUpdate);
@@ -115,10 +108,11 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase
{
$classMetadata = $this->getMockClassMetadata();
$objectManager = $this->getMockObjectManager();
- $persister = $this->getMockPersister();
$entity = new Listener\Entity(1);
+ $persister = $this->getMockPersister($entity, 'index', 'type');
$eventArgs = $this->createLifecycleEventArgs($entity, $objectManager);
+ $indexable = $this->getMockIndexable('index', 'type', $entity);
$objectManager->expects($this->any())
->method('getClassMetadata')
@@ -130,7 +124,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase
->with($entity, 'id')
->will($this->returnValue($entity->getId()));
- $listener = $this->createListener($persister, get_class($entity), array());
+ $listener = $this->createListener($persister, array(), $indexable);
$listener->preRemove($eventArgs);
$this->assertEquals($entity->getId(), current($listener->scheduledForDeletion));
@@ -146,11 +140,12 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase
{
$classMetadata = $this->getMockClassMetadata();
$objectManager = $this->getMockObjectManager();
- $persister = $this->getMockPersister();
$entity = new Listener\Entity(1);
$entity->identifier = 'foo';
+ $persister = $this->getMockPersister($entity, 'index', 'type');
$eventArgs = $this->createLifecycleEventArgs($entity, $objectManager);
+ $indexable = $this->getMockIndexable('index', 'type', $entity);
$objectManager->expects($this->any())
->method('getClassMetadata')
@@ -162,7 +157,7 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase
->with($entity, 'identifier')
->will($this->returnValue($entity->getId()));
- $listener = $this->createListener($persister, get_class($entity), array(), 'identifier');
+ $listener = $this->createListener($persister, array(), $indexable, 'identifier');
$listener->preRemove($eventArgs);
$this->assertEquals($entity->identifier, current($listener->scheduledForDeletion));
@@ -174,36 +169,6 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase
$listener->postFlush($eventArgs);
}
- /**
- * @dataProvider provideInvalidIsIndexableCallbacks
- * @expectedException \RuntimeException
- */
- public function testInvalidIsIndexableCallbacks($isIndexableCallback)
- {
- $listener = $this->createListener($this->getMockPersister(), 'FOS\ElasticaBundle\Tests\Doctrine\Listener\Entity', array());
- $listener->setIsIndexableCallback($isIndexableCallback);
- }
-
- public function provideInvalidIsIndexableCallbacks()
- {
- return array(
- array('nonexistentEntityMethod'),
- array(array(new Listener\IndexableDecider(), 'internalMethod')),
- array(42),
- array('entity.getIsIndexable() && nonexistentEntityFunction()'),
- );
- }
-
- public function provideIsIndexableCallbacks()
- {
- return array(
- array('getIsIndexable'),
- array(array(new Listener\IndexableDecider(), 'isIndexable')),
- array(function(Listener\Entity $entity) { return $entity->getIsIndexable(); }),
- array('entity.getIsIndexable()')
- );
- }
-
abstract protected function getLifecycleEventArgsClass();
abstract protected function getListenerClass();
@@ -240,9 +205,48 @@ abstract class ListenerTest extends \PHPUnit_Framework_TestCase
->getMock();
}
- private function getMockPersister()
+ private function getMockPersister($object, $indexName, $typeName)
{
- return $this->getMock('FOS\ElasticaBundle\Persister\ObjectPersisterInterface');
+ $mock = $this->getMockBuilder('FOS\ElasticaBundle\Persister\ObjectPersister')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $mock->expects($this->any())
+ ->method('handlesObject')
+ ->with($object)
+ ->will($this->returnValue(true));
+
+ $index = $this->getMockBuilder('Elastica\Index')->disableOriginalConstructor()->getMock();
+ $index->expects($this->any())
+ ->method('getName')
+ ->will($this->returnValue($indexName));
+ $type = $this->getMockBuilder('Elastica\Type')->disableOriginalConstructor()->getMock();
+ $type->expects($this->any())
+ ->method('getName')
+ ->will($this->returnValue($typeName));
+ $type->expects($this->any())
+ ->method('getIndex')
+ ->will($this->returnValue($index));
+
+ $mock->expects($this->any())
+ ->method('getType')
+ ->will($this->returnValue($type));
+
+ return $mock;
+ }
+
+ private function getMockIndexable($indexName, $typeName, $object, $return = null)
+ {
+ $mock = $this->getMock('FOS\ElasticaBundle\Provider\IndexableInterface');
+
+ if (null !== $return) {
+ $mock->expects($this->once())
+ ->method('isObjectIndexable')
+ ->with($indexName, $typeName, $object)
+ ->will($this->returnValue($return));
+ }
+
+ return $mock;
}
}
@@ -251,33 +255,15 @@ namespace FOS\ElasticaBundle\Tests\Doctrine\Listener;
class Entity
{
private $id;
- private $isIndexable;
- public function __construct($id, $isIndexable = true)
+ public function __construct($id)
{
$this->id = $id;
- $this->isIndexable = $isIndexable;
}
public function getId()
{
return $this->id;
}
-
- public function getIsIndexable()
- {
- return $this->isIndexable;
- }
}
-class IndexableDecider
-{
- public function isIndexable(Entity $entity)
- {
- return $entity->getIsIndexable();
- }
-
- protected function internalMethod()
- {
- }
-}
diff --git a/Tests/Functional/IndexableCallbackTest.php b/Tests/Functional/IndexableCallbackTest.php
new file mode 100644
index 0000000..89fca1d
--- /dev/null
+++ b/Tests/Functional/IndexableCallbackTest.php
@@ -0,0 +1,51 @@
+
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+namespace FOS\ElasticaBundle\Tests\Functional;
+
+/**
+ * @group functional
+ */
+class IndexableCallbackTest extends WebTestCase
+{
+ /**
+ * 2 reasons for this test:
+ *
+ * 1) To test that the configuration rename from is_indexable_callback under the listener
+ * key is respected, and
+ * 2) To test the Extension's set up of the Indexable service.
+ */
+ public function testIndexableCallback()
+ {
+ $client = $this->createClient(array('test_case' => 'ORM'));
+
+ /** @var \FOS\ElasticaBundle\Provider\Indexable $in */
+ $in = $client->getContainer()->get('fos_elastica.indexable');
+
+ $this->assertTrue($in->isObjectIndexable('index', 'type', new TypeObj()));
+ $this->assertFalse($in->isObjectIndexable('index', 'type2', new TypeObj()));
+ $this->assertFalse($in->isObjectIndexable('index', 'type3', new TypeObj()));
+ }
+
+ protected function setUp()
+ {
+ parent::setUp();
+
+ $this->deleteTmpDir('ORM');
+ }
+
+ protected function tearDown()
+ {
+ parent::tearDown();
+
+ $this->deleteTmpDir('ORM');
+ }
+}
diff --git a/Tests/Functional/TypeObj.php b/Tests/Functional/TypeObj.php
new file mode 100644
index 0000000..c264e7b
--- /dev/null
+++ b/Tests/Functional/TypeObj.php
@@ -0,0 +1,25 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace FOS\ElasticaBundle\Tests\Functional;
+
+class TypeObj
+{
+ public function isIndexable()
+ {
+ return true;
+ }
+
+ public function isntIndexable()
+ {
+ return false;
+ }
+}
diff --git a/Tests/Functional/app/Basic/config.yml b/Tests/Functional/app/Basic/config.yml
index 7025532..09e5aec 100644
--- a/Tests/Functional/app/Basic/config.yml
+++ b/Tests/Functional/app/Basic/config.yml
@@ -50,4 +50,4 @@ fos_elastica:
_parent:
type: "parent"
property: "parent"
- identifier: "id"
\ No newline at end of file
+ identifier: "id"
diff --git a/Tests/Functional/app/ORM/bundles.php b/Tests/Functional/app/ORM/bundles.php
new file mode 100644
index 0000000..d0b6efb
--- /dev/null
+++ b/Tests/Functional/app/ORM/bundles.php
@@ -0,0 +1,11 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace FOS\ElasticaBundle\Tests\Provider;
+
+use FOS\ElasticaBundle\Provider\Indexable;
+
+class IndexableTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider provideIsIndexableCallbacks
+ */
+ public function testValidIndexableCallbacks($callback, $return)
+ {
+ $indexable = new Indexable(array(
+ 'index/type' => $callback
+ ));
+ $index = $indexable->isObjectIndexable('index', 'type', new Entity);
+
+ $this->assertEquals($return, $index);
+ }
+
+ /**
+ * @dataProvider provideInvalidIsIndexableCallbacks
+ * @expectedException \InvalidArgumentException
+ */
+ public function testInvalidIsIndexableCallbacks($callback)
+ {
+ $indexable = new Indexable(array(
+ 'index/type' => $callback
+ ));
+ $indexable->isObjectIndexable('index', 'type', new Entity);
+ }
+
+ public function provideInvalidIsIndexableCallbacks()
+ {
+ return array(
+ array('nonexistentEntityMethod'),
+ array(array(new IndexableDecider(), 'internalMethod')),
+ array(42),
+ array('entity.getIsIndexable() && nonexistentEntityFunction()'),
+ );
+ }
+
+ public function provideIsIndexableCallbacks()
+ {
+ return array(
+ array('isIndexable', false),
+ array(array(new IndexableDecider(), 'isIndexable'), true),
+ array(function(Entity $entity) { return $entity->maybeIndex(); }, true),
+ array('entity.maybeIndex()', true),
+ array('!object.isIndexable() && entity.property == "abc"', true),
+ array('entity.property != "abc"', false),
+ );
+ }
+}
+
+class Entity
+{
+ public $property = 'abc';
+
+ public function isIndexable()
+ {
+ return false;
+ }
+
+ public function maybeIndex()
+ {
+ return true;
+ }
+}
+
+class IndexableDecider
+{
+ public function isIndexable(Entity $entity)
+ {
+ return !$entity->isIndexable();
+ }
+
+ protected function internalMethod()
+ {
+ }
+}
diff --git a/composer.json b/composer.json
index 8783822..d67e329 100644
--- a/composer.json
+++ b/composer.json
@@ -21,6 +21,7 @@
},
"require-dev":{
"doctrine/orm": "~2.2",
+ "doctrine/doctrine-bundle": "~1.2@beta",
"doctrine/mongodb-odm": "1.0.*@dev",
"propel/propel1": "1.6.*",
"pagerfanta/pagerfanta": "1.0.*@dev",