Example #1
0
 /**
  * Sets the attribute
  *
  * @param AttributeInterface $attribute
  *
  * @throws ColumnLabelException
  */
 public function setAttribute(AttributeInterface $attribute = null)
 {
     $this->attribute = $attribute;
     if (null === $attribute) {
         $this->locale = null;
         $this->scope = null;
         $this->suffixes = $this->rawSuffixes;
         $this->propertyPath = lcfirst(Inflector::classify($this->name));
     } else {
         if (!in_array($attribute->getBackendType(), [AbstractAttributeType::BACKEND_TYPE_REF_DATA_OPTION, AbstractAttributeType::BACKEND_TYPE_REF_DATA_OPTIONS])) {
             $this->propertyPath = $attribute->getBackendType();
         } else {
             $this->propertyPath = $attribute->getReferenceDataName();
         }
         $suffixes = $this->rawSuffixes;
         if ($attribute->isLocalizable()) {
             if (count($suffixes)) {
                 $this->locale = array_shift($suffixes);
             } else {
                 throw new ColumnLabelException('The column "%column%" must contain a locale code', ['%column%' => $this->label]);
             }
         }
         if ($attribute->isScopable()) {
             if (count($suffixes)) {
                 $this->scope = array_shift($suffixes);
             } else {
                 throw new ColumnLabelException('The column "%column%" must contain a scope code', ['%column%' => $this->label]);
             }
         }
         $this->suffixes = $suffixes;
     }
 }
 /**
  * Sets the attribute
  *
  * @param AttributeInterface $attribute
  *
  * @throws ColumnLabelException
  */
 public function setAttribute(AttributeInterface $attribute = null)
 {
     $this->attribute = $attribute;
     if (null === $attribute) {
         $this->locale = null;
         $this->scope = null;
         $this->suffixes = $this->rawSuffixes;
         $this->propertyPath = lcfirst(Inflector::classify($this->name));
     } else {
         $this->propertyPath = $attribute->getBackendType();
         $suffixes = $this->rawSuffixes;
         if ($attribute->isLocalizable()) {
             if (count($suffixes)) {
                 $this->locale = array_shift($suffixes);
             } else {
                 throw new ColumnLabelException('The column "%column%" must contain a locale code', array('%column%' => $this->label));
             }
         }
         if ($attribute->isScopable()) {
             if (count($suffixes)) {
                 $this->scope = array_shift($suffixes);
             } else {
                 throw new ColumnLabelException('The column "%column%" must contain a scope code', array('%column%' => $this->label));
             }
         }
         $this->suffixes = $suffixes;
     }
 }
 function it_throws_an_exception_when_the_locale_is_not_provided($qb, AttributeInterface $attribute)
 {
     $attribute->getCode()->willReturn('my_code');
     $attribute->getBackendType()->willReturn('options');
     $attribute->getAttributeType()->willReturn('pim_catalog_simpleselect');
     $this->shouldThrow('\\InvalidArgumentException')->duringAddAttributeSorter($attribute, 'desc', null, 'ecommerce');
 }
 function it_returns_not_blank_and_datetime_constraints(AttributeInterface $attribute)
 {
     $attribute->isRequired()->willReturn(true);
     $attribute->getBackendType()->willReturn(AbstractAttributeType::BACKEND_TYPE_DATETIME);
     $constraints = $this->guessConstraints($attribute);
     $constraints->shouldHaveCount(2);
     $constraints->offsetGet(0)->shouldReturnAnInstanceOf('Symfony\\Component\\Validator\\Constraints\\NotBlank');
     $constraints->offsetGet(1)->shouldReturnAnInstanceOf('Symfony\\Component\\Validator\\Constraints\\DateTime');
 }
 /**
  * {@inheritdoc}
  */
 public function addData($data)
 {
     $backendType = $this->attribute->getBackendType();
     if (substr($backendType, -1, 1) === 's') {
         $backendType = substr($backendType, 0, strlen($backendType) - 1);
     }
     $name = 'add' . ucfirst($backendType);
     return $this->{$name}($data);
 }
 function it_normalizes_value_with_decimal_support_backend(ProductValueInterface $value, AttributeInterface $attribute)
 {
     $attribute->getCode()->willReturn('code');
     $attribute->getBackendType()->willReturn('decimal');
     $attribute->isLocalizable()->willReturn(false);
     $attribute->isScopable()->willReturn(false);
     $value->getData()->willReturn('42.42');
     $value->getAttribute()->willReturn($attribute);
     $this->normalize($value, 'mongodb_json', [])->shouldReturn(['code' => 42.42]);
 }
 /**
  * @param ClassMetadata      $metadata
  * @param Constraint         $constraint
  * @param AttributeInterface $attribute
  */
 protected function addConstraint(ClassMetadata $metadata, Constraint $constraint, AttributeInterface $attribute)
 {
     $target = $constraint->getTargets();
     if (is_array($target)) {
         throw new \LogicException('No support provided for constraint on many targets');
     } elseif (Constraint::PROPERTY_CONSTRAINT === $target) {
         $metadata->addPropertyConstraint($attribute->getBackendType(), $constraint);
     } elseif (Constraint::CLASS_CONSTRAINT === $target) {
         $metadata->addConstraint($constraint);
     }
 }
 function let(QueryBuilder $qb, AttributeValidatorHelper $attrValidatorHelper, Expr $expr, AttributeInterface $image)
 {
     $this->beConstructedWith($attrValidatorHelper, ['pim_catalog_image', 'pim_catalog_file'], ['STARTS WITH', 'ENDS WITH', 'CONTAINS', 'DOES NOT CONTAIN', '=', 'EMPTY']);
     $this->setQueryBuilder($qb);
     $qb->getRootAlias()->willReturn('p');
     $qb->expr()->willReturn($expr);
     $image->getId()->willReturn(1);
     $image->getCode()->willReturn('picture');
     $image->isLocalizable()->willReturn(false);
     $image->isScopable()->willReturn(false);
     $image->getBackendType()->willReturn('media');
 }
 function it_normalizes_a_product_value_into_mongodb_document($mongoFactory, $serializer, ProductValueInterface $value, AttributeInterface $attribute, \MongoDBRef $mongoDBRef, \MongoId $mongoId)
 {
     $context = ['_id' => $mongoId, 'collection_name' => 'product'];
     $mongoFactory->createMongoId()->willReturn($mongoId);
     $mongoFactory->createMongoDBRef('product', $mongoId)->willReturn($mongoDBRef);
     $attribute->getId()->willReturn(123);
     $attribute->getBackendType()->willReturn('text');
     $value->getAttribute()->willReturn($attribute);
     $value->getData()->willReturn('my description');
     $value->getLocale()->willReturn(null);
     $value->getScope()->willReturn(null);
     $this->normalize($value, 'mongodb_document', $context)->shouldReturn(['_id' => $mongoId, 'attribute' => 123, 'entity' => $mongoDBRef, 'text' => 'my description']);
 }
 function it_sets_the_locale_and_scope_when_denormalizing_values($serializer, AttributeInterface $attribute)
 {
     $attribute->getAttributeType()->willReturn('pim_catalog_number');
     $attribute->getBackendType()->willReturn('decimal');
     $attribute->isLocalizable()->willReturn(true);
     $attribute->isScopable()->willReturn(true);
     $serializer->denormalize(1, 'pim_catalog_number', 'json', Argument::type('array'))->shouldBeCalled()->willReturn(1);
     $value = $this->denormalize(['value' => 1, 'locale' => 'en_US', 'scope' => 'ecommerce'], 'Pim\\Bundle\\CatalogBundle\\Model\\ProductValue', 'json', ['attribute' => $attribute]);
     $value->shouldBeAnInstanceOf('Pim\\Bundle\\CatalogBundle\\Model\\ProductValue');
     $value->getData()->shouldReturn(1);
     $value->getLocale()->shouldReturn('en_US');
     $value->getScope()->shouldReturn('ecommerce');
 }
 /**
  * {@inheritdoc}
  */
 public function addAttributeSorter(AttributeInterface $attribute, $direction, $locale = null, $scope = null)
 {
     $aliasPrefix = 'sorter';
     $joinAlias = $aliasPrefix . 'V' . $attribute->getCode();
     $backendType = $attribute->getBackendType();
     // join to value
     $condition = $this->prepareAttributeJoinCondition($attribute, $joinAlias, $locale, $scope);
     $this->qb->leftJoin($this->qb->getRootAlias() . '.values', $joinAlias, 'WITH', $condition);
     $joinAliasMetric = $aliasPrefix . 'M' . $attribute->getCode();
     $this->qb->leftJoin($joinAlias . '.' . $backendType, $joinAliasMetric);
     $this->qb->addOrderBy($joinAliasMetric . '.baseData', $direction);
     $idField = $this->qb->getRootAlias() . '.id';
     $this->qb->addOrderBy($idField);
     return $this;
 }
 function it_adds_a_sorter_to_the_query($qb, AttributeInterface $metric)
 {
     $metric->getId()->willReturn(42);
     $metric->getCode()->willReturn('metric_code');
     $metric->getBackendType()->willReturn('metric');
     $metric->isLocalizable()->willReturn(false);
     $metric->isScopable()->willReturn(false);
     $condition = "sorterVmetric_code.attribute = 42";
     $qb->getRootAlias()->willReturn('r');
     $qb->leftJoin('r.values', 'sorterVmetric_code', 'WITH', $condition)->shouldBeCalled();
     $qb->leftJoin('sorterVmetric_code.metric', 'sorterMmetric_code')->shouldBeCalled();
     $qb->addOrderBy('sorterMmetric_code.baseData', 'DESC')->shouldBeCalled();
     $qb->addOrderBy('r.id')->shouldBeCalled();
     $this->addAttributeSorter($metric, 'DESC');
 }
 /**
  * {@inheritdoc}
  */
 public function guessConstraints(AttributeInterface $attribute)
 {
     $constraints = array();
     if ($attribute->isRequired()) {
         $constraints[] = new Constraints\NotBlank();
     }
     switch ($attribute->getBackendType()) {
         case AbstractAttributeType::BACKEND_TYPE_DATE:
             $constraints[] = new Constraints\Date();
             break;
         case AbstractAttributeType::BACKEND_TYPE_DATETIME:
             $constraints[] = new Constraints\DateTime();
             break;
     }
     return $constraints;
 }
 function it_adds_an_equal_filter_on_an_attribute_in_the_query($qb, $attrValidatorHelper, AttributeInterface $attribute, Expr $expr)
 {
     $attribute->getBackendType()->willReturn('backend_type');
     $attribute->getCode()->willReturn('code');
     $attribute->getId()->willReturn(42);
     $attribute->isLocalizable()->willReturn(false);
     $attribute->isScopable()->willReturn(false);
     $attrValidatorHelper->validateLocale($attribute, Argument::any())->shouldBeCalled();
     $attrValidatorHelper->validateScope($attribute, Argument::any())->shouldBeCalled();
     $qb->expr()->willReturn($expr);
     $qb->getRootAlias()->willReturn('p');
     $expr->eq(Argument::any(), true)->willReturn('filtercode.backend_type = true');
     $expr->literal(true)->willReturn(true);
     $qb->innerJoin('p.values', Argument::any(), 'WITH', Argument::any())->shouldBeCalled();
     $this->addAttributeFilter($attribute, '=', true);
 }
 function it_adds_an_attribute_sorter_to_the_query($qb, AttributeInterface $sku)
 {
     $sku->getId()->willReturn(42);
     $sku->getCode()->willReturn('sku');
     $sku->getBackendType()->willReturn('varchar');
     $sku->isLocalizable()->willReturn(false);
     $sku->isScopable()->willReturn(false);
     $qb->expr()->willReturn(new Expr());
     $qb->getRootAlias()->willReturn('p');
     $qb->getDQLPart('join')->willReturn([]);
     $qb->resetDQLPart('join')->shouldBeCalled();
     $condition = "sorterVsku.attribute = 42";
     $qb->leftJoin('p.values', 'sorterVsku', 'WITH', $condition)->shouldBeCalled();
     $qb->addOrderBy('sorterVsku.varchar', 'DESC')->shouldBeCalled();
     $qb->getRootAlias()->willReturn('p');
     $qb->addOrderBy("p.id")->shouldBeCalled();
     $this->addAttributeSorter($sku, 'DESC');
 }
 /**
  * {@inheritdoc}
  */
 public function addAttributeSorter(AttributeInterface $attribute, $direction, $locale = null, $scope = null)
 {
     $aliasPrefix = 'sorter';
     $joinAlias = $aliasPrefix . 'V' . $attribute->getCode();
     $backendType = $attribute->getBackendType();
     // join to value and sort on
     $condition = $this->prepareAttributeJoinCondition($attribute, $joinAlias, $locale, $scope);
     // Remove current join in order to put the orderBy related join
     // at first place in the join queue for performances reasons
     $joinsSet = $this->qb->getDQLPart('join');
     $this->qb->resetDQLPart('join');
     $this->qb->leftJoin($this->qb->getRootAlias() . '.values', $joinAlias, 'WITH', $condition);
     $this->qb->addOrderBy($joinAlias . '.' . $backendType, $direction);
     $idField = $this->qb->getRootAlias() . '.id';
     $this->qb->addOrderBy($idField);
     // Reapply previous join after the orderBy related join
     // TODO : move this part in re-usable class
     $this->applyJoins($joinsSet);
     return $this;
 }
 /**
  * {@inheritdoc}
  */
 public function addAttributeSorter(AttributeInterface $attribute, $direction, $locale = null, $scope = null)
 {
     $aliasPrefix = 'sorter';
     $joinAlias = $aliasPrefix . 'V' . $attribute->getCode();
     $backendType = $attribute->getBackendType();
     if (null === $locale) {
         throw new \InvalidArgumentException(sprintf('Cannot prepare condition on type "%s" without locale', $attribute->getAttributeType()));
     }
     // join to value
     $condition = $this->prepareAttributeJoinCondition($attribute, $joinAlias, $locale, $scope);
     $this->qb->leftJoin($this->qb->getRootAlias() . '.values', $joinAlias, 'WITH', $condition);
     // then to option and option value to sort on
     $joinAliasOpt = $aliasPrefix . 'O' . $attribute->getCode();
     $condition = $joinAliasOpt . ".attribute = " . $attribute->getId();
     $this->qb->leftJoin($joinAlias . '.' . $backendType, $joinAliasOpt, 'WITH', $condition);
     $joinAliasOptVal = $aliasPrefix . 'OV' . $attribute->getCode();
     $condition = $joinAliasOptVal . '.locale = ' . $this->qb->expr()->literal($locale);
     $this->qb->leftJoin($joinAliasOpt . '.optionValues', $joinAliasOptVal, 'WITH', $condition);
     $this->qb->addOrderBy($joinAliasOpt . '.code', $direction);
     $this->qb->addOrderBy($joinAliasOptVal . '.value', $direction);
     $idField = $this->qb->getRootAlias() . '.id';
     $this->qb->addOrderBy($idField);
     return $this;
 }
 /**
  * {@inheritdoc}
  */
 public function supportAttribute(AttributeInterface $attribute)
 {
     $availableTypes = [AbstractAttributeType::BACKEND_TYPE_VARCHAR, AbstractAttributeType::BACKEND_TYPE_DATE, AbstractAttributeType::BACKEND_TYPE_DATETIME, AbstractAttributeType::BACKEND_TYPE_DECIMAL, AbstractAttributeType::BACKEND_TYPE_INTEGER];
     return in_array($attribute->getBackendType(), $availableTypes);
 }
 /**
  * Add non empty filter to the query
  *
  * @param AttributeInterface $attribute
  * @param string             $operator
  * @param string             $value
  * @param string             $locale
  * @param string             $scope
  */
 protected function addNonEmptyFilter(AttributeInterface $attribute, $operator, $value, $locale = null, $scope = null)
 {
     $backendType = $attribute->getBackendType();
     $joinAlias = $this->getUniqueAlias('filter' . $attribute->getCode(), true);
     // inner join to value
     $condition = $this->prepareAttributeJoinCondition($attribute, $joinAlias, $locale, $scope);
     $this->qb->innerJoin($this->qb->getRootAlias() . '.values', $joinAlias, 'WITH', $condition);
     $joinAliasOpt = $this->getUniqueAlias('filterM' . $attribute->getCode());
     $backendField = sprintf('%s.%s', $joinAliasOpt, 'baseData');
     $condition = $this->prepareCriteriaCondition($backendField, $operator, $value);
     $this->qb->innerJoin($joinAlias . '.' . $backendType, $joinAliasOpt, 'WITH', $condition);
 }
 /**
  * return bool
  */
 protected function isBackendTypeReferenceData()
 {
     return in_array($this->attribute->getBackendType(), [AbstractAttributeType::BACKEND_TYPE_REF_DATA_OPTION, AbstractAttributeType::BACKEND_TYPE_REF_DATA_OPTIONS]);
 }
 function it_adds_an_empty_filter_in_the_query($currencyManager, QueryBuilder $queryBuilder, AttributeInterface $price, Expr $expr, Comparison $comparison)
 {
     $price->getId()->willReturn(42);
     $price->getCode()->willReturn('price');
     $price->getBackendType()->willReturn('prices');
     $price->isLocalizable()->willReturn(false);
     $price->isScopable()->willReturn(false);
     $queryBuilder->expr()->willReturn(new Expr());
     $queryBuilder->getRootAlias()->willReturn('p');
     $value = ['data' => null, 'currency' => 'EUR'];
     $currencyManager->getActiveCodes()->willReturn(['EUR', 'USD']);
     $queryBuilder->leftJoin('p.values', Argument::any(), 'WITH', Argument::any())->shouldBeCalled();
     $queryBuilder->leftJoin(Argument::any(), Argument::any())->shouldBeCalled();
     $queryBuilder->expr()->willReturn($expr);
     $expr->literal('EUR')->willReturn('EUR');
     $expr->eq(Argument::any(), 'EUR')->willReturn($comparison);
     $expr->isNull(Argument::any())->willReturn('filterPprice.data IS NULL');
     $expr->isNull(Argument::any())->willReturn('filterPprice.id IS NULL');
     $expr->orX(Argument::any(), Argument::any())->shouldBeCalled();
     $queryBuilder->andWhere(null)->shouldBeCalled();
     $this->addAttributeFilter($price, 'EMPTY', $value);
 }
 function it_returns_null_when_unknown_backendtype($context, ProductValueComplete $constraint, ProductValueInterface $productValue, AttributeInterface $attribute)
 {
     $constraint->getChannel()->willReturn($this->getChannel());
     $metric = new Metric();
     $productValue->getMetric()->willReturn($metric);
     $productValue->getData()->willReturn('data');
     $attribute->getBackendType()->willReturn('unknown_metric');
     $productValue->getAttribute()->willReturn($attribute);
     $context->buildViolation(Argument::any())->shouldNotBeCalled();
     $this->validate($productValue, $constraint);
 }
 /**
  * @param AttributeInterface $attribute      the attribute
  * @param string             $joinAlias      the join alias
  * @param string             $joinAliasMedia the join alias
  */
 protected function addMediaLeftJoin(AttributeInterface $attribute, $joinAlias, $joinAliasMedia)
 {
     $backendType = $attribute->getBackendType();
     $this->qb->leftJoin($joinAlias . '.' . $backendType, $joinAliasMedia);
 }
 public function it_does_not_guess_unique_value(AttributeInterface $attribute)
 {
     $attribute->getBackendType()->willReturn(AbstractAttributeType::BACKEND_TYPE_VARCHAR);
     $attribute->isUnique()->willReturn(false);
     $this->guessConstraints($attribute)->shouldReturn([]);
 }
 function it_throws_an_exception_when_given_an_incorrect_label_length(AttributeInterface $attribute)
 {
     $this->beConstructedWith('name-en_US');
     $attribute->isLocalizable()->willReturn(true);
     $attribute->isScopable()->willReturn(true);
     $attribute->getBackendType()->willReturn(null);
     $this->shouldThrow(new ColumnLabelException('The column "%column%" must contain a scope code', array('%column%' => 'name-en_US')))->during('setAttribute', [$attribute]);
 }
 function it_throws_exception_when_the_field_name_is_not_consistent_with_the_channel_locale($managerRegistry, IdentifiableObjectRepositoryInterface $repository, AttributeInterface $attribute, IdentifiableObjectRepositoryInterface $channelRepository, IdentifiableObjectRepositoryInterface $localeRepository, LocaleInterface $locale, ChannelInterface $channel)
 {
     // localizable without the associated locale not in the channel
     $attribute->getCode()->willReturn('description');
     $attribute->isLocalizable()->willReturn(true);
     $attribute->isScopable()->willReturn(true);
     $attribute->getBackendType()->willReturn('text');
     $attribute->isLocaleSpecific()->willReturn(false);
     $attributeInfos = ['attribute' => $attribute, 'locale_code' => 'de_DE', 'scope_code' => 'mobile'];
     $managerRegistry->getRepository(self::ATTRIBUTE_CLASS)->willReturn($repository);
     $repository->findOneByIdentifier('description')->willReturn($attribute);
     $managerRegistry->getRepository(self::CHANNEL_CLASS)->shouldBeCalled()->willReturn($channelRepository);
     $channelRepository->findOneByIdentifier($attributeInfos['scope_code'])->shouldBeCalled()->willReturn($channel);
     $managerRegistry->getRepository(self::LOCALE_CLASS)->shouldBeCalled()->willReturn($localeRepository);
     $localeRepository->findOneByIdentifier($attributeInfos['locale_code'])->shouldBeCalled()->willReturn($locale);
     $channel->hasLocale($locale)->shouldBeCalled()->willReturn(false);
     $this->shouldThrow(new \InvalidArgumentException('The locale "de_DE" of the field "description-de_DE-mobile" is not available in scope "mobile"'))->duringExtractAttributeFieldNameInfos('description-de_DE-mobile');
 }
 function it_merges_columns_which_represents_price_attribute_value_in_many_columns($fieldExtractor, AttributeInterface $price)
 {
     $row = ['price-EUR' => '10', 'price-USD' => '12', 'price-CHF' => '14'];
     $attributeInfoEur = ['attribute' => $price, 'locale_code' => null, 'scope_code' => null, 'price_currency' => 'EUR'];
     $fieldExtractor->extractColumnInfo('price-EUR')->willReturn($attributeInfoEur);
     $attributeInfoUsd = ['attribute' => $price, 'locale_code' => null, 'scope_code' => null, 'price_currency' => 'USD'];
     $fieldExtractor->extractColumnInfo('price-USD')->willReturn($attributeInfoUsd);
     $attributeInfoChf = ['attribute' => $price, 'locale_code' => null, 'scope_code' => null, 'price_currency' => 'CHF'];
     $fieldExtractor->extractColumnInfo('price-CHF')->willReturn($attributeInfoChf);
     $price->getCode()->willReturn('price');
     $price->getBackendType()->willReturn('prices');
     $mergedRow = ['price' => '10 EUR,12 USD,14 CHF'];
     $this->merge($row)->shouldReturn($mergedRow);
 }
 /**
  * Check the consistency of the field with the attribute and it properties locale, scope, currency
  *
  * @param AttributeInterface $attribute
  * @param string             $fieldName
  * @param array              $explodedFieldName
  *
  * @throws \InvalidArgumentException
  */
 protected function checkFieldNameTokens(AttributeInterface $attribute, $fieldName, array $explodedFieldName)
 {
     // the expected number of tokens in a field may vary,
     //  - with the current price import, the currency can be optionally present in the header,
     //  - with the current metric import, a "-unit" field can be added in the header,
     //
     // To avoid BC break, we keep the support in this fix, a next minor version could contain only the
     // support of currency code in the header and metric in a single field
     $isLocalizable = $attribute->isLocalizable();
     $isScopable = $attribute->isScopable();
     $isPrice = 'prices' === $attribute->getBackendType();
     $isMetric = 'metric' === $attribute->getBackendType();
     if ($isLocalizable && $isScopable && $isPrice) {
         $expectedSize = [3, 4];
     } elseif ($isLocalizable && $isScopable && $isMetric) {
         $expectedSize = [3, 4];
     } elseif ($isLocalizable && $isScopable) {
         $expectedSize = [3];
     } elseif ($isLocalizable && $isPrice) {
         $expectedSize = [2, 3];
     } elseif ($isScopable && $isPrice) {
         $expectedSize = [2, 3];
     } elseif ($isLocalizable && $isMetric) {
         $expectedSize = [2, 3];
     } elseif ($isScopable && $isMetric) {
         $expectedSize = [2, 3];
     } elseif ($isLocalizable) {
         $expectedSize = [2];
     } elseif ($isScopable) {
         $expectedSize = [2];
     } elseif ($isPrice) {
         $expectedSize = [1, 2];
     } elseif ($isMetric) {
         $expectedSize = [1, 2];
     } else {
         $expectedSize = [1];
     }
     $nbTokens = count($explodedFieldName);
     if (!in_array($nbTokens, $expectedSize)) {
         $expected = [$isLocalizable ? 'a locale' : 'no locale', $isScopable ? 'a scope' : 'no scope', $isPrice ? 'an optional currency' : 'no currency'];
         $expected = implode($expected, ', ');
         throw new \InvalidArgumentException(sprintf('The field "%s" is not well-formatted, attribute "%s" expects %s', $fieldName, $attribute->getCode(), $expected));
     }
     if ($isLocalizable) {
         $this->checkForLocaleSpecificValue($attribute, $explodedFieldName);
     }
 }
 function it_logs_error_when_the_maximum_number_of_indexes_is_reached($collection, AttributeInterface $description, $namingUtility, $logger)
 {
     $description->getCode()->willReturn('description');
     $description->getBackendType()->willReturn('varchar');
     $description->isLocalizable()->willReturn(true);
     $description->isScopable()->willReturn(false);
     $description->isUseableAsGridFilter()->willReturn(true);
     $description->getAttributeType()->willReturn('pim_catalog_textarea');
     $namingUtility->getAttributeNormFields($description)->willReturn(['normalizedData.description-en_US', 'normalizedData.description-de_DE']);
     $indexes = array_fill(0, 64, 'fake_index');
     $collection->getIndexInfo()->willReturn($indexes);
     $logger->error(Argument::any())->shouldBeCalled();
     $collection->ensureIndex(Argument::any(), Argument::any())->shouldNotBeCalled();
     $this->ensureIndexesFromAttribute($description);
 }
 /**
  * @param AttributeInterface $attribute
  * @param array              $value
  * @param string             $operator
  * @param string             $locale
  * @param string             $scope
  */
 protected function addNonEmptyFilter(AttributeInterface $attribute, array $value, $operator, $locale = null, $scope = null)
 {
     $backendType = $attribute->getBackendType();
     $joinAlias = $this->getUniqueAlias('filter' . $attribute->getCode(), true);
     // join to value
     $condition = $this->prepareAttributeJoinCondition($attribute, $joinAlias, $locale, $scope);
     $this->qb->innerJoin($this->qb->getRootAlias() . '.values', $joinAlias, 'WITH', $condition);
     $joinAliasPrice = $this->getUniqueAlias('filterP' . $attribute->getCode());
     $condition = $this->preparePriceCondition($value, $joinAliasPrice, $operator);
     $this->qb->innerJoin($joinAlias . '.' . $backendType, $joinAliasPrice, 'WITH', $condition);
 }