function it_adds_invalid_values_to_product($groupRepository, $validator, $templateUpdater, GroupInterface $variantGroup, ProductInterface $product, StepExecution $stepExecution, JobConfigurationRepositoryInterface $jobConfigurationRepo, JobExecution $jobExecution, JobConfigurationInterface $jobConfiguration, ProductTemplateInterface $productTemplate) { $violation = new ConstraintViolation('error2', 'spec', [], '', '', $product); $violations = new ConstraintViolationList([$violation, $violation]); $validator->validate($product)->willReturn($violations); $stepExecution->getJobExecution()->willReturn($jobExecution); $jobConfigurationRepo->findOneBy(['jobExecution' => $jobExecution])->willReturn($jobConfiguration); $jobConfiguration->getConfiguration()->willReturn(json_encode(['filters' => [], 'actions' => ['field' => 'variant_group', 'value' => 'variant_group_code']])); $groupRepository->findOneByIdentifier('variant_group_code')->willReturn($variantGroup); $product->getVariantGroup()->willReturn(null); $variantGroup->addProduct($product)->shouldBeCalled(); $variantGroup->getProductTemplate()->willReturn($productTemplate); $templateUpdater->update($variantGroup->getProductTemplate(), [$product]); $stepExecution->addWarning(Argument::cetera())->shouldBeCalled(); $stepExecution->incrementSummaryInfo('skipped_products')->shouldBeCalled(); $this->setStepExecution($stepExecution); $this->process($product); }
function it_sets_invalid_values_to_attributes($validator, $productUpdater, AttributeInterface $attribute, AttributeRepositoryInterface $attributeRepository, ProductInterface $product, ConstraintViolationListInterface $violations, StepExecution $stepExecution, JobConfigurationRepositoryInterface $jobConfigurationRepo, JobExecution $jobExecution, JobConfigurationInterface $jobConfiguration) { $stepExecution->getJobExecution()->willReturn($jobExecution); $jobConfigurationRepo->findOneBy(['jobExecution' => $jobExecution])->willReturn($jobConfiguration); $values = ['categories' => [['scope' => null, 'locale' => null, 'data' => ['office', 'bedroom']]]]; $normalizedValues = addslashes(json_encode($values)); $jobConfiguration->getConfiguration()->willReturn(json_encode(['filters' => [], 'actions' => ['normalized_values' => $normalizedValues, 'ui_locale' => 'fr_FR', 'attribute_locale' => 'en_US']])); $validator->validate($product)->willReturn($violations); $violation = new ConstraintViolation('error2', 'spec', [], '', '', $product); $violations = new ConstraintViolationList([$violation, $violation]); $validator->validate($product)->willReturn($violations); $attributeRepository->findOneByIdentifier('categories')->willReturn($attribute); $product->isAttributeEditable($attribute)->willReturn(true); $productUpdater->update($product, $values)->shouldBeCalled(); $this->setStepExecution($stepExecution); $stepExecution->addWarning(Argument::cetera())->shouldBeCalled(); $stepExecution->incrementSummaryInfo('skipped_products')->shouldBeCalled(); $this->process($product); }
function it_throws_an_exception_if_no_job_configuration_is_found($jobConfigurationRepo, StepExecution $stepExecution, JobExecution $jobExecution) { $stepExecution->getJobExecution()->willReturn($jobExecution); $jobConfigurationRepo->findOneBy(['jobExecution' => $jobExecution])->willReturn(null); $this->setStepExecution($stepExecution); $this->shouldThrow('Doctrine\\ORM\\EntityNotFoundException')->during('read'); }
function it_normalizes_a_step_execution(StepExecution $stepExecution, BatchStatus $status, \DateTime $startTime, $translator) { $stepExecution->getStepName()->willReturn('export'); $translator->trans('export')->willReturn('Export step'); $stepExecution->getSummary()->willReturn(['read' => 12, 'write' => 50]); $translator->trans('job_execution.summary.read')->willReturn('Read'); $translator->trans('job_execution.summary.write')->willReturn('Write'); $stepExecution->getStatus()->willReturn($status); $status->getValue()->willReturn(9); $translator->trans('pim_import_export.batch_status.9')->willReturn('PENDING'); $stepExecution->getStartTime()->willReturn($startTime); $stepExecution->getEndTime()->willReturn(null); $startTime->getTimestamp()->willReturn(1411400461); $utcStartTime = new \DateTime(); $utcStartTime->setTimestamp(1411400461); $finalDate = $utcStartTime->format('Y-m-d g:i:s A'); $stepExecution->getWarnings()->willReturn(new ArrayCollection([new Warning($stepExecution->getWrappedObject(), 'a_warning', 'warning_reason', ['foo' => 'bar'], ['a' => 'A', 'b' => 'B', 'c' => 'C'])])); $translator->trans('a_warning')->willReturn('Reader'); $translator->trans(12)->willReturn(12); $translator->trans(50)->willReturn(50); $translator->trans('warning_reason', ['foo' => 'bar'])->willReturn('WARNING!'); $stepExecution->getFailureExceptions()->willReturn([['message' => 'a_failure', 'messageParameters' => ['foo' => 'bar']]]); $translator->trans('a_failure', ['foo' => 'bar'])->willReturn('FAIL!'); $this->normalize($stepExecution, 'any')->shouldReturn(['label' => 'Export step', 'status' => 'PENDING', 'summary' => ['Read' => 12, 'Write' => 50], 'startedAt' => $finalDate, 'endedAt' => null, 'warnings' => [['label' => 'Reader', 'reason' => 'WARNING!', 'item' => ['a' => 'A', 'b' => 'B', 'c' => 'C']]], 'failures' => ['FAIL!']]); }
/** * @param ProductInterface $product */ protected function incrementCount(ProductInterface $product) { if ($product->getId()) { $this->stepExecution->incrementSummaryInfo('process'); } else { $this->stepExecution->incrementSummaryInfo('create'); } }
function it_reads_several_entities_from_a_yml_file_incrementing_summary_info(StepExecution $stepExecution) { $this->beConstructedWith(true, false); $stepExecution->incrementSummaryInfo('read_lines')->shouldBeCalled(); $this->setFilePath(realpath(__DIR__ . '/../../../../../../features/Context/fixtures/fake_products_with_code.yml')); $this->setStepExecution($stepExecution); $this->read()->shouldReturn(['mug_akeneo' => ['sku' => 'mug_akeneo'], 't_shirt_akeneo_purple' => ['sku' => 't_shirt_akeneo_purple', 'color' => 'purple'], 'mouse_akeneo' => ['sku' => 'mouse_akeneo']]); }
/** * @param object $item */ protected function incrementCount($item) { if ($item->getId()) { $this->stepExecution->incrementSummaryInfo('process'); } else { $this->stepExecution->incrementSummaryInfo('create'); } }
function it_increments_summary_info(StepExecution $stepExecution, ProductInterface $product1, ProductInterface $product2) { $product1->getId()->willReturn('45'); $product2->getId()->willReturn(null); $stepExecution->incrementSummaryInfo('process')->shouldBeCalled(); $stepExecution->incrementSummaryInfo('create')->shouldBeCalled(); $this->setStepExecution($stepExecution); $this->write([$product1, $product2]); }
/** * @param array $objects */ protected function incrementCount(array $objects) { foreach ($objects as $object) { if ($object->getId()) { $this->stepExecution->incrementSummaryInfo('process'); } else { $this->stepExecution->incrementSummaryInfo('create'); } } }
/** * Returns the messages for a step execution * * @param StepExecution $stepExecution * * @return string */ protected function getStepExecutionMessages(StepExecution $stepExecution) { $message = ''; foreach ($stepExecution->getFailureExceptions() as $exception) { $message .= $this->getFailureExceptionMessage(sprintf('STEP %s', $stepExecution->getStepName()), $exception); } foreach ($stepExecution->getWarnings() as $warning) { $message .= $this->getWarningMessage($warning); } return $message; }
function it_throws_an_exception_if_an_error_occurs_during_processing($transformer, $validator, $managerRegistry, ProductInterface $product, ColumnInfo $columnInfo, ObjectManager $objectManager, StepExecution $stepExecution) { $item = ['sku' => 'AKNTS', 'family' => 'tshirts', 'groups' => 'akeneo_tshirt', 'categories' => 'tshirts,goodies', 'SUBSTITUTION-groups' => '', 'SUBSTITUTION-products' => 'AKNTS_WPS,AKNTS_PBS,AKNTS_PWS', 'description-en_US-mobile' => '<p>Akeneo T-Shirt</p>', 'not_empty_attribute' => '']; $transformer->transform('Pim\\Component\\Catalog\\Model\\Product', $item, ['enabled' => true])->willReturn($product); $transformer->getErrors('Pim\\Component\\Catalog\\Model\\Product')->willReturn([]); $transformer->getTransformedColumnsInfo('Pim\\Component\\Catalog\\Model\\Product')->willReturn([$columnInfo]); $validator->validate($product, [$columnInfo], $item, [])->willReturn(['AKNTS' => [["The value \"\" for not empty attribute \"not_empty_attribute\" is empty"]]]); $managerRegistry->getManagerForClass(Argument::type('string'))->willReturn($objectManager); $stepExecution->incrementSummaryInfo('skip')->shouldBeCalled(); $this->setStepExecution($stepExecution); $this->shouldThrow(new InvalidItemException('AKNTS: ', $item))->duringProcess($item); }
/** * {@inheritdoc} */ public function read() { if (null === $this->results) { $items = $this->readItems(); $this->results = new \ArrayIterator($items); } if (null !== ($result = $this->results->current())) { $this->results->next(); $this->stepExecution->incrementSummaryInfo('read'); } return $result; }
/** * @param array $products */ protected function incrementCount(array $products) { foreach ($products as $product) { foreach ($product->getAssociations() as $association) { $count = count($association->getProducts()) + count($association->getGroups()); $action = $association->getId() ? 'process' : 'create'; for ($i = 0; $i < $count; $i++) { $this->stepExecution->incrementSummaryInfo($action); } } } }
/** * {@inheritdoc} */ public function read() { if (!$this->isExecuted) { $this->isExecuted = true; $this->results = $this->getResults(); } if (null !== ($result = $this->results->current())) { $this->results->next(); $this->stepExecution->incrementSummaryInfo('read'); } return $result; }
/** * Fetch medias in local filesystem * * @param GroupInterface $variantGroup * @param string $directory */ protected function fetchMedia(GroupInterface $variantGroup, $directory) { if (null === ($productTemplate = $variantGroup->getProductTemplate())) { return; } $identifier = $variantGroup->getCode(); $this->variantGroupUpdater->update($variantGroup, ['values' => $productTemplate->getValuesData()]); $this->mediaFetcher->fetchAll($productTemplate->getValues(), $directory, $identifier); foreach ($this->mediaFetcher->getErrors() as $error) { $this->stepExecution->addWarning($error['message'], [], new DataInvalidItem($error['media'])); } }
function let(NotificationManager $manager, JobExecutionEvent $event, JobExecution $jobExecution, StepExecution $stepExecution, ArrayCollection $warnings, JobInstance $jobInstance, UserInterface $user, BatchStatus $status) { $this->beConstructedWith($manager); $jobExecution->getUser()->willReturn($user); $jobExecution->getStepExecutions()->willReturn([$stepExecution]); $jobExecution->getStatus()->willReturn($status); $jobExecution->getJobInstance()->willReturn($jobInstance); $stepExecution->getWarnings()->willReturn($warnings); $jobExecution->getId()->willReturn(5); $jobInstance->getType()->willReturn('export'); $jobInstance->getLabel()->willReturn('Product export'); $event->getJobExecution()->willReturn($jobExecution); }
function it_adds_invalid_values_to_product($propertyAdder, $validator, ProductInterface $product, StepExecution $stepExecution, JobConfigurationRepositoryInterface $jobConfigurationRepo, JobExecution $jobExecution, JobConfigurationInterface $jobConfiguration) { $violation = new ConstraintViolation('error2', 'spec', [], '', '', $product); $violations = new ConstraintViolationList([$violation, $violation]); $validator->validate($product)->willReturn($violations); $stepExecution->getJobExecution()->willReturn($jobExecution); $jobConfigurationRepo->findOneBy(['jobExecution' => $jobExecution])->willReturn($jobConfiguration); $jobConfiguration->getConfiguration()->willReturn(json_encode(['filters' => [], 'actions' => [['field' => 'categories', 'value' => ['office', 'bedroom']]]])); $propertyAdder->addData($product, 'categories', ['office', 'bedroom'])->shouldBeCalled(); $stepExecution->addWarning(Argument::cetera())->shouldBeCalled(); $stepExecution->incrementSummaryInfo('skipped_products')->shouldBeCalled(); $this->setStepExecution($stepExecution); $this->process($product); }
function it_reads_products($entityManager, $jobRepository, JobConfigurationRepositoryInterface $jobConfigurationRepo, JobInstance $jobInstance, JobExecution $jobExecution, JobConfigurationInterface $jobConfiguration, ProductQueryBuilderFactory $pqbFactory, ProductQueryBuilder $pqb, StepExecution $stepExecution, Cursor $cursor, ProductInterface $product, EntityRepository $customEntityRepository) { $jobRepository->getJobManager()->willReturn($entityManager); $stepExecution->getJobExecution()->willReturn($jobExecution); $customEntityRepository->findOneBy(['code' => 'update_product_value'])->willReturn($jobInstance); $jobInstance->getJobExecutions()->willReturn(new ArrayCollection([$jobExecution])); $jobConfigurationRepo->findOneBy(['jobExecution' => $jobExecution])->willReturn($jobConfiguration); $pqbFactory->create()->willReturn($pqb); $jobConfiguration->getConfiguration()->willReturn(json_encode(['filters' => [], 'actions' => []])); $pqb->execute()->willReturn($cursor); $cursor->next()->shouldBeCalled(); $stepExecution->incrementSummaryInfo('read')->shouldBeCalledTimes(1); $this->setStepExecution($stepExecution); $cursor->current()->willReturn($product); $this->read()->shouldReturn($product); }
/** * Sets an item as skipped and throws an invalid item exception. * * @param array $item * @param ConstraintViolationListInterface $violations * @param \Exception $previousException * * @throws InvalidItemException */ protected function skipItemWithConstraintViolations(array $item, ConstraintViolationListInterface $violations, \Exception $previousException = null) { if ($this->stepExecution) { $this->stepExecution->incrementSummaryInfo('skip'); } throw new InvalidItemFromViolationsException($violations, new FileInvalidItem($item, $this->stepExecution->getSummaryInfo('read_lines') + 1), [], 0, $previousException); }
/** * @param int $nbSkippedProducts * @param array $skippedMessages */ protected function incrementSkippedProductsCount($nbSkippedProducts, $skippedMessages) { $this->stepExecution->incrementSummaryInfo('skip_products', $nbSkippedProducts); foreach ($skippedMessages as $productIdentifier => $messages) { $this->stepExecution->addWarning($this->getName(), sprintf('Copy of values to product "%s" skipped.', $productIdentifier), [], $messages); } }
/** * {@inheritdoc} */ public function read() { $this->documentManager->clear(); if (!$this->executed) { $this->executed = true; if (!is_object($this->channel)) { $this->channel = $this->channelManager->getChannelByCode($this->channel); } if ($this->missingCompleteness) { $this->completenessManager->generateMissingForChannel($this->channel); } $this->query = $this->repository->buildByChannelAndCompleteness($this->channel)->getQuery(); $this->products = $this->getQuery()->execute(); // MongoDB Cursor are not positioned on first element (whereas ArrayIterator is) // as long as getNext() hasn't be called $this->products->getNext(); } $result = $this->products->current(); if ($result) { $this->metricConverter->convert($result, $this->channel); $this->stepExecution->incrementSummaryInfo('read'); $this->products->next(); } return $result; }
/** * Sets errors on items * * @param array $item * @param array $errors * * @throws InvalidItemException */ protected function setItemErrors(array $item, array $errors) { if ($this->stepExecution) { $this->stepExecution->incrementSummaryInfo('skip'); } throw new InvalidItemException(implode("\n", $this->getErrorMessages($errors)), $item); }
/** * @param FlatItemBuffer $buffer * @param array $writerOptions * @param int $maxLinesPerFile * @param string $basePathname * * @return array */ protected function writeIntoSeveralFiles(FlatItemBuffer $buffer, array $writerOptions, $maxLinesPerFile, $basePathname) { $writtenFiles = []; $basePathPattern = $this->getNumberedPathname($basePathname); $writtenLinesCount = 0; $fileCount = 1; $headers = $this->sortHeaders($buffer->getHeaders()); $hollowItem = array_fill_keys($headers, ''); foreach ($buffer as $count => $incompleteItem) { if (0 === $writtenLinesCount % $maxLinesPerFile) { $filePath = $this->resolveFilePath($buffer, $maxLinesPerFile, $basePathPattern, $fileCount); $writtenLinesCount = 0; $writer = $this->getWriter($filePath, $writerOptions); $writer->addRow($headers); } $item = array_replace($hollowItem, $incompleteItem); $writer->addRow($item); $writtenLinesCount++; if (null !== $this->stepExecution) { $this->stepExecution->incrementSummaryInfo('write'); } if (0 === $writtenLinesCount % $maxLinesPerFile || $buffer->count() === $count + 1) { $writer->close(); $writtenFiles[] = $filePath; $fileCount++; } } return $writtenFiles; }
/** * @param array $headers * * @return array */ protected function sortHeaders(array $headers) { if (null !== $this->columnSorter) { $headers = $this->columnSorter->sort($headers, $this->stepExecution->getJobParameters()->all()); } return $headers; }
/** * Fetch medias on the local filesystem * * @param ProductInterface $product * @param string $directory */ protected function fetchMedia(ProductInterface $product, $directory) { $identifier = $product->getIdentifier()->getData(); $this->mediaFetcher->fetchAll($product->getValues(), $directory, $identifier); foreach ($this->mediaFetcher->getErrors() as $error) { $this->stepExecution->addWarning($error['message'], [], new DataInvalidItem($error['media'])); } }
function it_executes_with_an_invalid_item_during_processing($reader, $processor, $writer, StepExecution $execution, EventDispatcherInterface $dispatcher, JobRepositoryInterface $repository, BatchStatus $status, ExitStatus $exitStatus) { $this->setBatchSize(3); $this->setEventDispatcher($dispatcher); $this->setJobRepository($repository); $execution->getStatus()->willReturn($status); $status->getValue()->willReturn(BatchStatus::STARTING); $dispatcher->dispatch(EventInterface::BEFORE_STEP_EXECUTION, Argument::any())->shouldBeCalled(); $execution->setStartTime(Argument::any())->shouldBeCalled(); $execution->setStatus(Argument::any())->shouldBeCalled(); // first batch $reader->read()->willReturn('r1', 'r2', 'r3', 'r4', null); $processor->process('r1')->shouldBeCalled()->willReturn('p1'); $processor->process('r2')->shouldBeCalled()->willReturn('p2'); $processor->process('r3')->shouldBeCalled()->willReturn('p3'); $writer->write(['p1', 'p2', 'p3'])->shouldBeCalled(); // second batch $processor->process('r4')->shouldBeCalled()->willThrow(new InvalidItemException('my msg', ['r4'])); $execution->addWarning(Argument::any(), Argument::any(), Argument::any(), Argument::any())->shouldBeCalled(); $dispatcher->dispatch(Argument::any(), Argument::any())->shouldBeCalled(); $processor->process(null)->shouldNotBeCalled(); $writer->write(['p4'])->shouldNotBeCalled(); $execution->getExitStatus()->willReturn($exitStatus); $exitStatus->getExitCode()->willReturn(ExitStatus::COMPLETED); $repository->updateStepExecution($execution)->shouldBeCalled(); $execution->isTerminateOnly()->willReturn(false); $execution->upgradeStatus(Argument::any())->shouldBeCalled(); $dispatcher->dispatch(EventInterface::STEP_EXECUTION_SUCCEEDED, Argument::any())->shouldBeCalled(); $dispatcher->dispatch(EventInterface::STEP_EXECUTION_COMPLETED, Argument::any())->shouldBeCalled(); $execution->setEndTime(Argument::any())->shouldBeCalled(); $execution->setExitStatus(Argument::any())->shouldBeCalled(); $this->execute($execution); }
/** * Return the job configuration * * @throws EntityNotFoundException * * @return array */ protected function getJobConfiguration() { $jobExecution = $this->stepExecution->getJobExecution(); $massEditJobConf = $this->jobConfigurationRepo->findOneBy(['jobExecution' => $jobExecution]); if (null === $massEditJobConf) { throw new EntityNotFoundException(sprintf('No JobConfiguration found for jobExecution with id %s', $jobExecution->getId())); } return json_decode(stripcslashes($massEditJobConf->getConfiguration()), true); }
/** * @param array $item * @param DataArrayConversionException $exception * * @throws InvalidItemException * @throws InvalidItemFromViolationsException */ protected function skipItemFromConversionException(array $item, DataArrayConversionException $exception) { if (null !== $this->stepExecution) { $this->stepExecution->incrementSummaryInfo('skip'); } if (null !== $exception->getViolations()) { throw new InvalidItemFromViolationsException($exception->getViolations(), new FileInvalidItem($item, $this->stepExecution->getSummaryInfo('read_lines') + 1), [], 0, $exception); } throw new InvalidItemException($exception->getMessage(), new FileInvalidItem($item, $this->stepExecution->getSummaryInfo('read_lines') + 1), [], 0, $exception); }
/** * Returns the filters from the configuration. * The parameters can be in the 'filters' root node, or in filters data node (e.g. for export). * * @return array */ protected function getConfiguredFilters() { $filters = $this->stepExecution->getJobParameters()->get('filters'); if (array_key_exists('data', $filters)) { $filters = $filters['data']; } return array_filter($filters, function ($filter) { return count($filter) > 0; }); }
function it_processes_a_family($jobConfigurationRepo, $attributeRepository, $channelRepository, $factory, StepExecution $stepExecution, ValidatorInterface $validator, FamilyInterface $family, JobExecution $jobExecution, JobConfigurationInterface $jobConfiguration, AttributeInterface $attributeColor, ChannelInterface $channelMobile, ChannelInterface $channelEcommerce, AttributeRequirementInterface $attrReqColorMobile, AttributeRequirementInterface $attrReqColorEcom) { $actions = [['attribute_code' => 'color', 'channel_code' => 'mobile', 'is_required' => true], ['attribute_code' => 'color', 'channel_code' => 'ecommerce', 'is_required' => false]]; $violations = new ConstraintViolationList([]); $validator->validate($family)->willReturn($violations); $stepExecution->getJobExecution()->willReturn($jobExecution); $attributeRepository->findOneByIdentifier('color')->willReturn($attributeColor); $channelRepository->findOneByIdentifier('mobile')->willReturn($channelMobile); $channelRepository->findOneByIdentifier('ecommerce')->willReturn($channelEcommerce); $jobConfigurationRepo->findOneBy(['jobExecution' => $jobExecution])->willReturn($jobConfiguration); $jobConfiguration->getConfiguration()->willReturn(json_encode(['filters' => [], 'actions' => $actions])); $factory->createAttributeRequirement($attributeColor, $channelMobile, true)->willReturn($attrReqColorMobile); $factory->createAttributeRequirement($attributeColor, $channelEcommerce, false)->willReturn($attrReqColorEcom); $this->setStepExecution($stepExecution); $family->addAttribute($attributeColor)->shouldBeCalledTimes(2); $family->addAttributeRequirement($attrReqColorMobile)->shouldBeCalled(); $family->addAttributeRequirement($attrReqColorEcom)->shouldBeCalled(); $this->process($family); }