Skip to content

Commit

Permalink
Move data cleaning code in a dedicated command
Browse files Browse the repository at this point in the history
  • Loading branch information
PierreGauthier committed Feb 9, 2024
1 parent 81147e2 commit c2abb94
Show file tree
Hide file tree
Showing 8 changed files with 200 additions and 87 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
- Open Sylius Admin, head to Configuration > Gally and configure the Gally endpoint (URL, credentials)
- Run this commands from your Sylius instance. This commands must be runned only once to synchronize the structure.
```shell
bin/console gally:structure-sync # Sync catalog et source field data with gally
bin/console gally:structure:sync # Sync catalog et source field data with gally
```
- Run a full index from Sylius to Gally. This command can be run only once. Afterwards, the modified products are automatically synchronized.
```shell
Expand All @@ -66,6 +66,10 @@
- At this step, you should be able to see your product and source field in the Gally backend.
- They should also appear in your Sylius frontend when searching or browsing categories.
- And you're done !
- You can also run the command to clean data that are not present in sylius anymore:
```shell
bin/console gally:structure:clean
```

## noUiSlider

Expand Down
65 changes: 65 additions & 0 deletions src/Command/StructureClean.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php
/**
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade Gally to newer versions in the future.
*
* @package Gally
* @author Stephan Hochdörfer <[email protected]>, Gally Team <[email protected]>
* @copyright 2022-present Smile
* @license Open Software License v. 3.0 (OSL-3.0)
*/

declare(strict_types=1);

namespace Gally\SyliusPlugin\Command;

use Gally\SyliusPlugin\Synchronizer\AbstractSynchronizer;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class StructureClean extends Command
{
protected static $defaultName = 'gally:structure:clean';

/**
* @param AbstractSynchronizer[] $synchronizers
*/
public function __construct(
private iterable $synchronizers
) {
parent::__construct();
}

protected function configure(): void
{
$this->setDescription('Remove all entity from gally that not exist anymore on sylius side.')
->addOption('force', 'f', InputOption::VALUE_NONE, 'Really remove the listed entity from the gally.')
->addOption('quiet', 'q', InputOption::VALUE_NONE, 'Don\'t list deleted entities.');
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$output->writeln('');
$isDryRun = !$input->getOption('force');
$isQuiet = $input->getOption('quiet');

if ($isDryRun) {
$output->writeln("<error>Running in dry run mode, add -f to really delete entities from Gally.</error>");
$output->writeln('');
}

foreach ($this->synchronizers as $synchronizer) {
$time = microtime(true);
$message = "<comment>Clean {$synchronizer->getEntityClass()}</comment>";
$output->writeln("$message ...");
$synchronizer->cleanAll($isDryRun, $isQuiet);
$time = number_format(microtime(true) - $time, 2);
$output->writeln(" Cleaned ($time)s\n");
}

return 0;
}
}
2 changes: 1 addition & 1 deletion src/Command/StructureSync.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

class StructureSync extends Command
{
protected static $defaultName = 'gally:structure-sync';
protected static $defaultName = 'gally:structure:sync';

/**
* @param AbstractSynchronizer[] $synchronizers
Expand Down
5 changes: 5 additions & 0 deletions src/Resources/config/services/commands.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,10 @@
<argument type="tagged_iterator" tag="gally.entity.indexer"/>
<tag name="console.command"/>
</service>

<service id="Gally\SyliusPlugin\Command\StructureClean">
<argument type="tagged_iterator" tag="gally.entity.synchronizer"/>
<tag name="console.command"/>
</service>
</services>
</container>
8 changes: 8 additions & 0 deletions src/Synchronizer/AbstractSynchronizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ public function fetchEntity(ModelInterface $entity): ?ModelInterface

abstract protected function getIdentity(ModelInterface $entity): string;

/**
* Remove all entity from gally that not exist anymore on sylius side.
*/
public function cleanAll(bool $dryRun = true, bool $quiet = false): void
{

}

protected function buildFetchAllParams(int $page): array
{
return [
Expand Down
60 changes: 42 additions & 18 deletions src/Synchronizer/CatalogSynchronizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,7 @@ public function getIdentity(ModelInterface $entity): string
public function synchronizeAll(): void
{
$this->fetchEntities();

$this->catalogCodes = array_flip($this->getAllEntityCodes());
$this->localizedCatalogSynchronizer->fetchEntities();
$this->localizedCatalogCodes = array_flip($this->localizedCatalogSynchronizer->getAllEntityCodes());

// synchronize all channels where the Gally integration is active
$channels = $this->channelRepository->findBy(['gallyActive' => 1]);
Expand All @@ -75,18 +72,6 @@ public function synchronizeAll(): void
foreach ($channels as $channel) {
$this->synchronizeItem(['channel' => $channel]);
}

foreach (array_flip($this->localizedCatalogCodes) as $localizedCatalogCode) {
/** @var LocalizedCatalogCatalogRead $localizedCatalog */
$localizedCatalog = $this->localizedCatalogSynchronizer->getEntityFromApi($localizedCatalogCode);
$this->localizedCatalogSynchronizer->deleteEntity($localizedCatalog->getId());
}

foreach (array_flip($this->catalogCodes) as $catalogCode) {
/** @var CatalogCatalogRead $catalog */
$catalog = $this->getEntityFromApi($catalogCode);
$this->deleteEntity($catalog->getId());
}
}

public function synchronizeItem(array $params): ?ModelInterface
Expand All @@ -108,12 +93,51 @@ public function synchronizeItem(array $params): ?ModelInterface
'locale' => $locale,
'catalog' => $catalog,
]);
}

unset($this->localizedCatalogCodes[$this->localizedCatalogSynchronizer->getIdentity($localizedCatalog)]);
return $catalog;
}

public function cleanAll(bool $dryRun = true, bool $quiet = false): void
{
$this->fetchEntities();

$this->catalogCodes = array_flip($this->getAllEntityCodes());
$this->localizedCatalogSynchronizer->fetchEntities();
$this->localizedCatalogCodes = array_flip($this->localizedCatalogSynchronizer->getAllEntityCodes());

// Synchronize all channels where the Gally integration is active
$channels = $this->channelRepository->findBy(['gallyActive' => 1]);

/** @var Channel[] $channels */
foreach ($channels as $channel) {
/** @var LocaleInterface $locale */
foreach ($channel->getLocales() as $locale) {
unset($this->localizedCatalogCodes[$channel->getCode() . '_' . $locale->getCode()]);
}
unset($this->catalogCodes[$channel->getCode()]);
}

unset($this->catalogCodes[$this->getIdentity($catalog)]);
foreach (array_flip($this->localizedCatalogCodes) as $localizedCatalogCode) {
/** @var LocalizedCatalogCatalogRead $localizedCatalog */
$localizedCatalog = $this->localizedCatalogSynchronizer->getEntityFromApi($localizedCatalogCode);
if (!$quiet) {
print(" Delete localized catalog {$localizedCatalog->getId()}\n");
}
if (!$dryRun) {
$this->localizedCatalogSynchronizer->deleteEntity($localizedCatalog->getId());
}
}

return $catalog;
foreach (array_flip($this->catalogCodes) as $catalogCode) {
/** @var CatalogCatalogRead $catalog */
$catalog = $this->getEntityFromApi($catalogCode);
if (!$quiet) {
print(" Delete catalog {$catalog->getId()}\n");
}
if (!$dryRun) {
$this->deleteEntity($catalog->getId());
}
}
}
}
52 changes: 43 additions & 9 deletions src/Synchronizer/SourceFieldOptionSynchronizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ public function getIdentity(ModelInterface $entity): string

public function synchronizeAll(): void
{
$this->sourceFieldOptionCodes = array_flip($this->getAllEntityCodes());
$this->sourceFieldSynchronizer->fetchEntities();

$metadataName = strtolower((new \ReflectionClass(Product::class))->getShortName());
Expand Down Expand Up @@ -134,12 +133,6 @@ public function synchronizeAll(): void
}

$this->runBulk();

foreach (array_flip($this->sourceFieldOptionCodes) as $sourceFieldOptionCode) {
/** @var SourceFieldOptionSourceFieldOptionRead $sourceFieldOption */
$sourceFieldOption = $this->getEntityFromApi($sourceFieldOptionCode);
$this->deleteEntity($sourceFieldOption->getId());
}
}

public function synchronizeItem(array $params): ?ModelInterface
Expand Down Expand Up @@ -172,11 +165,52 @@ public function synchronizeItem(array $params): ?ModelInterface
$sourceFieldOption = new SourceFieldOptionSourceFieldOptionWrite($data);
$this->addEntityToBulk($sourceFieldOption);

unset($this->sourceFieldOptionCodes[$this->getIdentity($sourceFieldOption)]);

return $sourceFieldOption;
}

public function cleanAll(bool $dryRun = true, bool $quiet = false): void
{
$this->sourceFieldOptionCodes = array_flip($this->getAllEntityCodes());
$this->sourceFieldSynchronizer->fetchEntities();

$metadataName = strtolower((new \ReflectionClass(Product::class))->getShortName());
/** @var MetadataMetadataRead $metadata */
$metadata = $this->metadataSynchronizer->synchronizeItem(['entity' => $metadataName]);

/** @var ProductAttribute[] $attributes */
$attributes = $this->productAttributeRepository->findAll();
foreach ($attributes as $attribute) {
if ('select' === $attribute->getType()) {
$sourceField = $this->sourceFieldSynchronizer->getEntityByCode($metadata, $attribute->getCode());
$configuration = $attribute->getConfiguration();
foreach ($configuration['choices'] ?? [] as $code => $choice) {
unset($this->sourceFieldOptionCodes['/source_fields/' . $sourceField->getId() . $code]);
}
}
}

/** @var ProductOption[] $options */
$options = $this->productOptionRepository->findAll();
foreach ($options as $option) {
$sourceField = $this->sourceFieldSynchronizer->getEntityByCode($metadata, $option->getCode());
/** @var ProductOptionValueInterface $value */
foreach ($option->getValues() as $value) {
unset($this->sourceFieldOptionCodes['/source_fields/' . $sourceField->getId() . $value->getCode()]);
}
}

foreach (array_flip($this->sourceFieldOptionCodes) as $sourceFieldOptionCode) {
/** @var SourceFieldOptionSourceFieldOptionRead $sourceFieldOption */
$sourceFieldOption = $this->getEntityFromApi($sourceFieldOptionCode);
if (!$quiet) {
print(" Delete sourceFieldOption {$sourceFieldOption->getSourceField()} {$sourceFieldOption->getCode()}\n");
}
if (!$dryRun) {
$this->deleteEntity($sourceFieldOption->getId());
}
}
}

public function fetchEntity(ModelInterface $entity): ?ModelInterface
{
/** @var SourceFieldOptionSourceFieldOptionWrite $entity */
Expand Down
Loading

0 comments on commit c2abb94

Please sign in to comment.