Permalink
Browse files

[Provider] Change provider construction (possible BC break)

 * Created AbstractProvider class (for all DB services), which handles the default batch_size option.
 * The logger Closure is now optional for populate().
 * Removed unused Elastica_Type argument from Provider constructors.
 * Added unit tests for Doctrine's AbstractProvider class.
 * The extra argument (ManagerRegistry) for Doctrine providers is now an appended constructor argument, so the extension no longer needs to use different replacement indexes for Propel/Doctrine providers.
  • Loading branch information...
1 parent 89a368a commit e09225eb0918505327ab624177dbe6016d2235ec @jmikola jmikola committed Mar 9, 2012
@@ -281,26 +281,14 @@ protected function loadTypeProvider(array $typeConfig, ContainerBuilder $contain
if (isset($typeConfig['provider']['service'])) {
return $typeConfig['provider']['service'];
}
- $abstractProviderId = sprintf('foq_elastica.provider.prototype.%s', $typeConfig['driver']);
+
$providerId = sprintf('foq_elastica.provider.%s.%s', $indexName, $typeName);
- $providerDef = new DefinitionDecorator($abstractProviderId);
+ $providerDef = new DefinitionDecorator('foq_elastica.provider.prototype.' . $typeConfig['driver']);
$providerDef->addTag('foq_elastica.provider', array('index' => $indexName, 'type' => $typeName));
- $providerDef->replaceArgument(0, $typeDef);
-
- // Doctrine has a mandatory service as second argument
- $argPos = ('propel' === $typeConfig['driver']) ? 1 : 2;
-
- $providerDef->replaceArgument($argPos, new Reference($objectPersisterId));
- $providerDef->replaceArgument($argPos + 1, $typeConfig['model']);
-
- $options = array('batch_size' => $typeConfig['provider']['batch_size']);
-
- if ('propel' !== $typeConfig['driver']) {
- $options['query_builder_method'] = $typeConfig['provider']['query_builder_method'];
- $options['clear_object_manager'] = $typeConfig['provider']['clear_object_manager'];
- }
-
- $providerDef->replaceArgument($argPos + 2, $options);
+ $providerDef->replaceArgument(0, new Reference($objectPersisterId));
+ $providerDef->replaceArgument(1, $typeConfig['model']);
+ // Propel provider can simply ignore Doctrine-specific options
+ $providerDef->replaceArgument(2, array_diff_key($typeConfig['provider'], array('service' => 1)));
$container->setDefinition($providerId, $providerDef);
return $providerId;
@@ -2,106 +2,85 @@
namespace FOQ\ElasticaBundle\Doctrine;
-use FOQ\ElasticaBundle\Provider\ProviderInterface;
+use Doctrine\Common\Persistence\ManagerRegistry;
use FOQ\ElasticaBundle\Persister\ObjectPersisterInterface;
-use Elastica_Type;
-use Elastica_Document;
-use Closure;
-use InvalidArgumentException;
+use FOQ\ElasticaBundle\Provider\AbstractProvider as BaseAbstractProvider;
-abstract class AbstractProvider implements ProviderInterface
+abstract class AbstractProvider extends BaseAbstractProvider
{
- /**
- * Elastica type
- *
- * @var Elastica_Type
- */
- protected $type;
-
- /**
- * Manager registry
- *
- * @var object
- */
- protected $registry;
+ protected $managerRegistry;
/**
- * Object persister
+ * Constructor.
*
- * @var ObjectPersisterInterface
+ * @param ObjectPersisterInterface $objectPersister
+ * @param string $objectClass
+ * @param array $options
+ * @param ManagerRegistry $managerRegistry
*/
- protected $objectPersister;
-
- /**
- * Provider options
- *
- * @var array
- */
- protected $options = array(
- 'batch_size' => 100,
- 'clear_object_manager' => true,
- 'query_builder_method' => 'createQueryBuilder'
- );
-
- public function __construct(Elastica_Type $type, $registry, ObjectPersisterInterface $objectPersister, $objectClass, array $options = array())
+ public function __construct(ObjectPersisterInterface $objectPersister, $objectClass, array $options, $managerRegistry)
{
- $this->type = $type;
- $this->registry = $registry;
- $this->objectClass = $objectClass;
- $this->objectPersister = $objectPersister;
- $this->options = array_merge($this->options, $options);
+ parent::__construct($objectPersister, $objectClass, array_merge(array(
+ 'clear_object_manager' => true,
+ 'query_builder_method' => 'createQueryBuilder',
+ ), $options));
+
+ $this->managerRegistry = $managerRegistry;
}
/**
- * Insert the repository objects in the type index
- *
- * @param Closure $loggerClosure
+ * @see FOQ\ElasticaBundle\Provider\ProviderInterface::populate()
*/
- public function populate(Closure $loggerClosure)
+ public function populate(\Closure $loggerClosure = null)
{
$queryBuilder = $this->createQueryBuilder();
- $nbObjects = $this->countObjects($queryBuilder);
+ $nbObjects = $this->countObjects($queryBuilder);
for ($offset = 0; $offset < $nbObjects; $offset += $this->options['batch_size']) {
+ if ($loggerClosure) {
+ $stepStartTime = microtime(true);
+ }
- $stepStartTime = microtime(true);
$objects = $this->fetchSlice($queryBuilder, $this->options['batch_size'], $offset);
$this->objectPersister->insertMany($objects);
if ($this->options['clear_object_manager']) {
- $this->registry->getManagerForClass($this->objectClass)->clear();
+ $this->managerRegistry->getManagerForClass($this->objectClass)->clear();
}
- $stepNbObjects = count($objects);
- $stepCount = $stepNbObjects+$offset;
- $objectsPerSecond = $stepNbObjects / (microtime(true) - $stepStartTime);
- $loggerClosure(sprintf('%0.1f%% (%d/%d), %d objects/s', 100*$stepCount/$nbObjects, $stepCount, $nbObjects, $objectsPerSecond));
+ if ($loggerClosure) {
+ $stepNbObjects = count($objects);
+ $stepCount = $stepNbObjects + $offset;
+ $percentComplete = 100 * $stepCount / $nbObjects;
+ $objectsPerSecond = $stepNbObjects / (microtime(true) - $stepStartTime);
+ $loggerClosure(sprintf('%0.1f%% (%d/%d), %d objects/s', $percentComplete, $stepCount, $nbObjects, $objectsPerSecond));
+ }
}
}
/**
- * Counts the objects of a query builder
+ * Counts objects that would be indexed using the query builder.
*
- * @param queryBuilder
- * @return int
- **/
+ * @param object $queryBuilder
+ * @return integer
+ */
protected abstract function countObjects($queryBuilder);
/**
- * Fetches a slice of objects
+ * Fetches a slice of objects using the query builder.
*
- * @param queryBuilder
- * @param int limit
- * @param int offset
- * @return array of objects
- **/
+ * @param object $queryBuilder
+ * @param integer $limit
+ * @param integer $offset
+ * @return array
+ */
protected abstract function fetchSlice($queryBuilder, $limit, $offset);
/**
- * Creates the query builder used to fetch the documents to index
+ * Creates the query builder, which will be used to fetch objects to index.
*
- * @return query builder
- **/
+ * @return object
+ */
protected abstract function createQueryBuilder();
}
@@ -2,42 +2,49 @@
namespace FOQ\ElasticaBundle\Doctrine\MongoDB;
+use Doctrine\ODM\MongoDB\Query\Builder;
use FOQ\ElasticaBundle\Doctrine\AbstractProvider;
+use FOQ\ElasticaBundle\Exception\InvalidArgumentTypeException;
class Provider extends AbstractProvider
{
/**
- * Counts the objects of a query builder
- *
- * @param queryBuilder
- * @return int
- **/
+ * @see FOQ\ElasticaBundle\Doctrine\AbstractProvider::countObjects()
+ */
protected function countObjects($queryBuilder)
{
- return $queryBuilder->getQuery()->count();
+ if (!$queryBuilder instanceof Builder) {
+ throw new InvalidArgumentTypeException($queryBuilder, 'Doctrine\ODM\MongoDB\Query\Builder');
+ }
+
+ return $queryBuilder
+ ->getQuery()
+ ->count();
}
/**
- * Fetches a slice of objects
- *
- * @param queryBuilder
- * @param int limit
- * @param int offset
- * @return array of objects
- **/
+ * @see FOQ\ElasticaBundle\Doctrine\AbstractProvider::fetchSlice()
+ */
protected function fetchSlice($queryBuilder, $limit, $offset)
{
- return $queryBuilder->limit($limit)->skip($offset)->getQuery()->execute()->toArray();
+ if (!$queryBuilder instanceof Builder) {
+ throw new InvalidArgumentTypeException($queryBuilder, 'Doctrine\ODM\MongoDB\Query\Builder');
+ }
+
+ return $queryBuilder
+ ->limit($limit)
+ ->skip($offset)
+ ->getQuery()
+ ->execute()
+ ->toArray();
}
/**
- * Creates the query builder used to fetch the documents to index
- *
- * @return query builder
- **/
+ * @see FOQ\ElasticaBundle\Doctrine\AbstractProvider::createQueryBuilder()
+ */
protected function createQueryBuilder()
{
- return $this->registry
+ return $this->managerRegistry
->getManagerForClass($this->objectClass)
->getRepository($this->objectClass)
->{$this->options['query_builder_method']}();
View
@@ -2,51 +2,59 @@
namespace FOQ\ElasticaBundle\Doctrine\ORM;
+use Doctrine\ORM\QueryBuilder;
use FOQ\ElasticaBundle\Doctrine\AbstractProvider;
+use FOQ\ElasticaBundle\Exception\InvalidArgumentTypeException;
class Provider extends AbstractProvider
{
/**
- * Counts the objects of a query builder
- *
- * @param queryBuilder
- * @return int
- **/
+ * @see FOQ\ElasticaBundle\Doctrine\AbstractProvider::countObjects()
+ */
protected function countObjects($queryBuilder)
{
+ if (!$queryBuilder instanceof QueryBuilder) {
+ throw new InvalidArgumentTypeException($queryBuilder, 'Doctrine\ORM\QueryBuilder');
+ }
+
+ /* Clone the query builder before altering its field selection and DQL,
+ * lest we leave the query builder in a bad state for fetchSlice().
+ */
$qb = clone $queryBuilder;
- $qb->select($qb->expr()->count($queryBuilder->getRootAlias()))
- ->resetDQLPart('orderBy'); // no need to order the query. It does not change the count and make the query less efficient.
- return $qb->getQuery()->getSingleScalarResult();
+ return $qb
+ ->select($qb->expr()->count($queryBuilder->getRootAlias()))
+ // Remove ordering for efficiency; it doesn't affect the count
+ ->resetDQLPart('orderBy')
+ ->getQuery()
+ ->getSingleScalarResult();
}
/**
- * Fetches a slice of objects
- *
- * @param queryBuilder
- * @param int limit
- * @param int offset
- * @return array of objects
- **/
+ * @see FOQ\ElasticaBundle\Doctrine\AbstractProvider::fetchSlice()
+ */
protected function fetchSlice($queryBuilder, $limit, $offset)
{
- $queryBuilder->setFirstResult($offset);
- $queryBuilder->setMaxResults($limit);
+ if (!$queryBuilder instanceof QueryBuilder) {
+ throw new InvalidArgumentTypeException($queryBuilder, 'Doctrine\ORM\QueryBuilder');
+ }
- return $queryBuilder->getQuery()->getResult();
+ return $queryBuilder
+ ->setFirstResult($offset)
+ ->setMaxResults($limit)
+ ->getQuery()
+ ->getResult();
}
/**
- * Creates the query builder used to fetch the documents to index
- *
- * @return query builder
- **/
+ * @see FOQ\ElasticaBundle\Doctrine\AbstractProvider::createQueryBuilder()
+ */
protected function createQueryBuilder()
{
- return $this->registry
+ return $this->managerRegistry
->getManagerForClass($this->objectClass)
->getRepository($this->objectClass)
+ // ORM query builders require an alias argument
->{$this->options['query_builder_method']}('a');
}
}
@@ -0,0 +1,11 @@
+<?php
+
+namespace FOQ\ElasticaBundle\Exception;
+
+class InvalidArgumentTypeException extends \InvalidArgumentException
+{
+ public function __construct($value, $expectedType)
+ {
+ parent::__construct(sprintf('Expected argument of type "%s", "%s" given', $expectedType, is_object($value) ? get_class($value) : gettype($value)));
+ }
+}
Oops, something went wrong.

0 comments on commit e09225e

Please sign in to comment.