diff --git a/LICENSE b/LICENSE index aeabcadc..f9713a98 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020 Webgriffe® +Copyright (c) 2023 Webgriffe® Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 86d89b46..6f203d1e 100644 --- a/README.md +++ b/README.md @@ -5,723 +5,28 @@
Plugin allowing to import data from Akeneo PIM to your Sylius store.
- - -> **Please note!!**+ Plugin allowing to import data from Akeneo PIM to your Sylius store. +
++ + -{% endif %} -``` - -### Importing configurable products, product options and their values - -If you have product models on Akeneo this plugin will create relative configurable products along with their variants on -Sylius. To make this possible **you must create on Sylius the product options with the same code of the related Akeneo's -family variant axes attributes**. You can leave the product options empty (without values) because they will be created -during actual product import. To do so you must configure the **product options value handler** in -the `config/packages/webgriffe_sylius_akeneo_plugin.yaml`: - -```yaml -# config/packages/webgriffe_sylius_akeneo_plugin.yaml - -webgriffe_sylius_akeneo: - # ... - value_handlers: - product: - # ... - product_option: - type: 'product_option' -``` - -The `product_option` value handler doesn't need any configuration; it must be configured only once, and it will handle -all the product options created on Sylius. - -### Importing product prices - -If you manage product prices on Akeneo you can import them on Sylius. To do so you have to configure the channel pricing -value handler in the `config/packages/webgriffe_sylius_akeneo_plugin.yaml` file: - -```yaml -# config/packages/webgriffe_sylius_akeneo_plugin.yaml - -webgriffe_sylius_akeneo: - # ... - value_handlers: - product: - # ... - price: - type: 'channel_pricing' - options: - $akeneoAttribute: 'price' -``` - -In the `$akeneoAttribute` option you have to set the code of the **Akeneo price attribute** where you store your -products prices. Then they will be imported into Sylius for channels whose base currency is the same as the price -currency on Akeneo. - -If you also manage the original price on Akeneo, you can import it using the same channel price value handler. Add -the `$syliusPropertyPath` option to the configuration and specify which price you are importing: price (default) or -original_price. -As above use the `$akeneoAttribute` option to specify the code of the **Akeneo original price attribute** where you -store your products original prices. - -```yaml -# config/packages/webgriffe_sylius_akeneo_plugin.yaml - -webgriffe_sylius_akeneo: - # ... - value_handlers: - product: - # ... - price: - type: 'channel_pricing' - options: - $akeneoAttribute: 'price' - $syliusPropertyPath: 'price' # Not required, it is the default - original_price: - type: 'channel_pricing' - options: - $akeneoAttribute: 'original_price' - $syliusPropertyPath: 'original_price' -``` - -### Importing product metrical properties - -**NB. This feature is only available from Akeneo PIM version 5** - -If you manage product metrical attributes on Akeneo you can import them on Sylius as product properties (like weight, -length, height and depth). To do this, you have to configure the metrical properties value handler in -the `config/packages/webgriffe_sylius_akeneo_plugin.yaml` file: - -```yaml -# config/packages/webgriffe_sylius_akeneo_plugin.yaml - -webgriffe_sylius_akeneo: - # ... - value_handlers: - product: - # ... - weight: - type: 'metric_property' - options: - $akeneoAttributeCode: 'weight' - $propertyPath: 'weight' - height: - type: 'metric_property' - options: - $akeneoAttributeCode: 'height' - $propertyPath: 'height' - $akeneoUnitMeasurementCode: 'CENTIMETER' -``` - -For each `metric_property` value handler you have to configure, in `$propertyPath`, the Sylius product property path of -the property where to store the value of the Akeneo attribute whose code is configured with `$akeneoAttributeCode`. Be -sure this is a metrical attribute on Akeneo. -In the same way you can import other product metrical properties like height and other custom properties you possibly -added to your store. -In addition, you can decide in which unit of measure to import the value. To do this, enter the desired Akeneo unit of -measurement code in the attribute `$akeneoUnitMeasurementCode`. If this field is not specified, the plugin will import -the value using Akeneo's standard unit of measure. -For more information about Akeneo's units of measurement, consult -the [documentation](https://help.akeneo.com/pim/serenity/articles/manage-your-measurements.html). - -### Importing product-taxons associations - -This plugin **will not import Akeneo categories into Sylius taxons**, but **it will associate Sylius products to -existing taxons** based on Akeneo product-categories associations. This plugin will associate products only to those -Sylius taxons which already exist on Sylius and have the same code of their related Akeneo categories. In this way, -products taxons association import does not need any configuration and you can have all the categories you want on -Akeneo, even those you don't want on your Sylius store. Indeed, if there are products associated to Akeneo categories -which doesn't exist on Sylius, the import will succeed with no error. - -So, all you have to do is to **create on Sylius those taxons that you want products associated with** when importing -from Akeneo, paying attention to **assign the same code** of the corresponding category on Akeneo. - -### Importing product associations - -This plugin will also import product associations. It's a zero configuration import. All you have to do is to **create -on Sylius the same association types that you have on Akeneo** paying attention to assign the same association type -code. If you have some association type on Akeneo that you don't need on your store, simply do not create it on Sylius -and product associations importer will ignore it. - -### Import data - -To actually import data from Akeneo PIM you have two options: import from UI in the admin section or from the CLI with -the **webgriffe:akeneo:import** command. -Import procedure assumes that [Symfony Messenger](https://symfony.com/doc/current/messenger.html) is installed and -working as required since Sylius v1.11. - -#### Import from admin Akeneo PIM button - -This button allows you to import a product directly from the admin index page. - -![Schedule Akeneo PIM import button](schedule-akeneo-import-button.png) - -#### Import from CLI - -To import multiple items at the same time you can use the `webgriffe:akeneo:import` console command: - -```bash -bin/console webgriffe:akeneo:import --since="2020-01-30" -``` - -This will import all Akeneo entities updated after the provided date. - -You can also use a "since file" where to read the since date: - -```bash -echo "2022-01-30" > var/storage/akeneo-sincefile.txt -bin/console webgriffe:akeneo:import --since-file="var/storage/akeneo-sincefile.txt" -``` - -When run with the since file, the import command will write the current date/time to the since file after the importing -process is terminated. This is useful when you put the import command in cron: - -```bash -* * * * * /usr/bin/php /path/to/sylius/bin/console -e prod -q webgriffe:akeneo:import --since-file=/path/to/sylius/var/storage/akeneo-import-sincefile.txt -``` - -This way the import command is run repeatedly importing only products modified since the last command execution. - -You can also import items only for specific importers: - -```bash -bin/console webgriffe:akeneno:import --importer="Product" --importer="MyImporter" --since="2020-01-30" -``` - -You can also import items regardless of their last update date: - -```bash -bin/console webgriffe:akeneno:import --all -``` - -### Products reconciliation - -Product reconciliation can be useful when one or more products are deleted on Akeneo. By default, reconciliation does -not delete products on Sylius but places them in a deactivated state. -This is because the Sylius structure does not allow you to delete products if they are associated with any order. -To reconcile the products you can use the webgriffe:akeneo:reconcile console command: - -```bash -bin/console webgriffe:akeneo:reconcile -``` - -It could be useful to add also this command to your scheduler to run automatically every day or whatever you want. - -### Suggested crontab - -To make all importers and other plugin features work automatically the following is the suggested crontab: - -``` -0 * * * * /path/to/sylius/bin/console -e prod -q webgriffe:akeneo:import --all --importer="AttributeOptions" -* * * * * /path/to/sylius/bin/console -e prod -q webgriffe:akeneo:import --since-file=/path/to/sylius/var/storage/akeneo-import-sincefile.txt --importer="Product" --importer="ProductAssociations" -0 */6 * * * /path/to/sylius/bin/console -e prod -q webgriffe:akeneo:reconcile -``` - -This will: - -* Import the update of all attribute options every hour -* Import, every minute, all products that have been modified since the last execution, along with their associations -* Reconcile Akeneo deleted products every 6 hours - -Import and Reconcile commands uses a [lock mechanism](https://symfony.com/doc/current/console/lockable_trait.html) which -prevents running them if another instance of the same command is already running. - -## Architecture & customization - -> This plugin makes use of [Symfony Messenger](https://symfony.com/doc/current/messenger.html) component. It is highly -> recommended to have a minimum knowledge of these component to understand how this integration works. - -This plugin has basically two entry points: - -* The UI admin import button, this will import only products -* The Import CLI command, this will import both product, product associations and attribute options - -Both this entry points deals to identify entities to import from Akeneo. When they have collected them they dispatch -an `Webgriffe\SyliusAkeneoPlugin\Message\ItemImport` message on the messenger default bus. -By default, in the configuration this message is handled by the main bus, the same bus used as default by Sylius for -catalog promotions. This means that, if you have configured the main bus to run synchronously the import will be -executed at the same time, otherwise it will be handled by the Messenger queue asynchronously. -We suggest to run it asynchronously especially if you plan to run the import command manually infrequently or with -option --all. - -To be able to import entities (or even only different parts of each entity), -the `Webgriffe\SyliusAkeneoPlugin\MessageHandler\ItemImportHandler` (the Messenger message handler) use an ** -importer registry** which holds all the registered **importers**. - -An importer is a service implementing the `Webgriffe\SyliusAkeneoPlugin\ImporterInterface` and that mainly holds the -logic about how to import its Akeneo entities. If you want to import from Akeneo other entities not implemented in this -plugin you have can implement your own importer. You can also replace an importer provided with this plugin by -decorating or replacing its service definition. - -To implement a new custom importer create a class which implements the `Webgriffe\SyliusAkeneoPlugin\ImporterInterface`: - -```php -// src/Importer/CustomImporter.php - -namespace App\Importer; - -use Webgriffe\SyliusAkeneoPlugin\ImporterInterface; - -final class CustomImporter implements ImporterInterface -{ - // ... -} -``` - -Then define the importer with the `webgriffe_sylius_akeneo.importer` tag: - -```yaml -# config/services.yaml - -app.custom.importer: - class: App\Importer\CustomImporter - tags: - - { name: 'webgriffe_sylius_akeneo.importer' } -``` - -Anyway, this plugin already implement the following importers. - -### Product Importer - -Akeneo is a PIM (Product Information Management) system so its job is to manage product data. For this reason, this -Sylius -Akeneo plugin is focused on importing products and provides a **product -importer** (`\Webgriffe\SyliusAkeneoPlugin\Product\Importer`). - -This product importer processes Akeneo product data through the following components: - -#### Taxons resolver - -A **taxons resolver** (`Webgriffe\SyliusAkeneoPlugin\Product\TaxonsResolverInterface`) which is responsible to return -the list of Sylius taxons for a given Akeneo product. The provided implementation of the taxons resolver is -the `Webgriffe\SyliusAkeneoPlugin\Product\AlreadyExistingTaxonsResolver` class which returns the already existent Sylius -taxons which have the same code as the related Akeneo categories. - -#### Product options resolver - -A **product options resolver** (`Webgriffe\SyliusAkeneoPlugin\Product\ProductOptionsResolverInterface`) which is -responsible to return the related Sylius's **product option(s)** when the product being imported is part of a parent -product model. The provided implementation of the product options resolver is -the `Webgriffe\SyliusAkeneoPlugin\Product\ProductOptionsResolver` class, which returns already existing product options -but also creates new ones if needed. - -#### Channels resolver - -A **channels resolver** (`Webgriffe\SyliusAkeneoPlugin\Product\ChannelsResolverInterface`) which is responsible to -return the list of Sylius channels where the products should be enabled. The provided implementation of the channels' -resolver is the `Webgriffe\SyliusAkeneoPlugin\Product\AllChannelsResolver` class which simply enables the product in all -available Sylius channels. - -#### Status resolver - -A **status resolver** (`Webgriffe\SyliusAkeneoPlugin\Product\StatusResolverInterface`) which is responsible to return -the Sylius product status (enabled or disabled, true or false). The provided implementation of the status resolver is -the `Webgriffe\SyliusAkeneoPlugin\Product\StatusResolver` which returns the same product status of the related Akeneo -product, but only if this doesn't belong to a parent product model, otherwise it will always return true (enabled). This -is because in Sylius the product status is at product level and not (also) at product variant level; instead, in Akeneo -the status is only at product level and not at product model level. So, in Akeneo, you could have only one disabled -product variant for a parent product which have several other variants enabled. This situation can't be mapped on Sylius -at present. - -#### Value handlers resolver - -A **value handlers resolver** (`Webgriffe\SyliusAkeneoPlugin\ValueHandlersResolverInterface`) which is responsible to -return a list of **value handlers** (`Webgriffe\SyliusAkeneoPlugin\ValueHandlerInterface`) for each Akeneo product -attribute value. - -The provided implementation of the value handlers resolver is -the `Webgriffe\SyliusAkeneoPlugin\PriorityValueHandlersResolver` which returns, for each attribute value, the list of -all the value handlers supporting that attribute value sorted by a priority. Each value handler returned by the resolver -for a given attribute is then called to handle that value. - -For more detail on how the Product importer works look at the code of -the `Webgriffe\SyliusAkeneoPlugin\Product\Importer::import()` method. - -#### Value handlers - -By default, the provided `Webgriffe\SyliusAkeneoPlugin\PriorityValueHandlersResolver` is configured with value handlers -specified in the `webgriffe_sylius_akeneo.value_handlers.product` array as explained in the configuration paragraph. -This plugin already provides some value handler implementations that are: - -* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\AttributeValueHandler` (type `generic_attribute`) it will automatically - handle Sylius attributes whose attribute code matches Akeneo attribute code. -* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\ChannelPricingValueHandler` (type `channel_pricing`): it sets the value - found on a given Akeneo price attribute (`options.$akeneoAttribute`) as the Sylius product's channels price or - original price for - channels whose base currency is the price currency of the Akeneo price. -* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\FileAttributeValueHandler` (type `file_attribute`): it saves the file - downloaded from the Akeneo file attribute (`options.$akeneoAttributeCode`) to the given destination - path (`options.$downloadPath`). -* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\GenericPropertyValueHandler` (type `generic_property`): using - the [Symfony's Property Access component](https://symfony.com/doc/current/components/property_access.html), it sets - the value found on a given Akeneo attribute (`options.$akeneoAttributeCode`) on a given property - path (`options.$propertyPath`) of both product and product variant. -* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\ImageValueHandler` (type `image`): it downloads the image found on a given - Akeneo image attribute (`options.$akeneoAttributeCode`) and sets it as a Sylius product image with a provided type - string (`options.$syliusImageType`). -* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\ImmutableSlugValueHandler` (type `immutable_slug`): it slugifies the value - found on a given Akeneo attribute (`options.$akeneoAttributeToSlugify`) and sets it on the Sylius slug product - translation property. -* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\MetricPropertyValueHandler` (type `metric_property`) using - the [Symfony's Property Access component](https://symfony.com/doc/current/components/property_access.html), it sets - the value found on a given Akeneo attribute (`options.$akeneoAttributeCode`) on a given property - path (`options.$propertyPath`) of both product and product variant. It automatically converts it to the default unit - of measurement or the one specified (`options.$akeneoUnitMeasurementCode`). -* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\ProductOptionValueHandler` (type `product_option`): it sets the value found - on a given Akeneo attribute as a Sylius product option value on the product variant. -* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\TranslatablePropertyValueHandler` (type `translatable_property`): using - the [Symfony's Property Access component](https://symfony.com/doc/current/components/property_access.html), it sets - the value found on a given Akeneo attribute (`options.$akeneoAttributeCode`) on a given property - path (`options.$translationPropertyPath`) of both product and product variant translations. - -To add a custom value handler to the resolver you can implement your own by implementing -the `Webgriffe\SyliusAkeneoPlugin\ValueHandlerInterface` and then tag it with -the `webgriffe_sylius_akeneo.product.value_handler` tag: - -```yaml -# config/services.yaml - -app.my_custom_value_handler: - class: App\MyCustomValueHandler - tags: - - { name: 'webgriffe_sylius_akeneo.product.value_handler', priority: 42 } -``` +
-### Product associations importer +## What does this plugin do? -Another provided importer is the **product associations -importer** (`Webgriffe\SyliusAkeneoPlugin\ProductAssociations\Importer`). This importer imports the Akeneo products -associations to the corresponding Sylius products associations. The association types must already exist on Sylius with -the same code they have on Akeneo. +The _SyliusAkeneoPlugin_ takes care of importing and updating products, product associations and attributes from _Akeneo_ to _Sylius_. -### Attribute options importer +## How can I install the plugin on my Sylius store? -Another provided importer is the **attribute options -importer** (`\Webgriffe\SyliusAkeneoPlugin\AttributeOptions\Importer`). This importer imports the Akeneo simple select -and multi select attributes options into Sylius select attributes. The select attributes must already exist on Sylius -with the same code they have on Akeneo. +Please, check the documentation at the [Installation](docs/installation.html) step. -## Contributing +## Where do I start? -See `docs/Contributing.md` file. +First, we recommend that you read the entire documentation. Then you could start to +install the plugin and use the basic features it gives such as the abandoned cart. You could also think to suggest some +new features that this plugin could add. So, let's start! 🚀 ## License diff --git a/UPGRADE-2.0.md b/UPGRADE-2.0.md deleted file mode 100644 index eda05484..00000000 --- a/UPGRADE-2.0.md +++ /dev/null @@ -1,181 +0,0 @@ -# UPGRADE FROM `v1.16.2` TO `v2.0.0` - -In the 2.0 version, we have introduced the Symfony Messenger component and removed all deprecations. Symfony Messenger -has allowed us to remove all the Queue manager infrastructure so that we can now focus only on the Akeneo - Sylius -exchange. Obviously, the removal of the queue has provoked also the removal of the admin queue page, which is useful for -some store managers to check for product imports, but we are already working on other solutions to provide a similar -tool to the administrators! - -Here you can find all the passages to upgrade your plugin to v2.0 starting from v1.16.2. Naturally, we have written all -the passages for a simple project without customizations. In this case, you can find more in the below section [Codebase](#Codebase) which -contains all the detailed edits applied to this version and, obviously all the BC contained in this major version. - -## Simple upgrade - -Remove occurrences of `Resources` in `config/packages/webgriffe_sylius_akeneo_plugin.yaml`: - -```diff -- - { resource: "@WebgriffeSyliusAkeneoPlugin/Resources/config/config.yaml" } -+ - { resource: "@WebgriffeSyliusAkeneoPlugin/config/config.yaml" } -``` - -Remove occurrences of `Resources` in `config/routes/webgriffe_sylius_akeneo_plugin.yaml` or where you import the plugin routes: - -```diff -webgriffe_sylius_akeneo_plugin_admin: -- resource: "@WebgriffeSyliusAkeneoPlugin/Resources/config/admin_routing.yaml" -+ resource: "@WebgriffeSyliusAkeneoPlugin/config/admin_routing.yaml" -``` - -Be sure that your configuration in `config/packages/webgriffe_sylius_akeneo_plugin.yaml` is already using the new name arguments -as specified [here](https://github.com/webgriffe/SyliusAkeneoPlugin/releases/tag/1.13.0). - -If you do not have already installed the official Ajeneo PHP SDK client we suggest to follow the installation instructions -showed [here](https://github.com/akeneo/api-php-client#installation). - -After having installed the Akeneo PIM client you can now require the new version of plugin: - -```bash -composer require webgriffe/sylius-akeneo-plugin ^2.0 -``` - -Run migration diff command and then execute it: - -```bash -bin/console doctrine:migrations:diff -bin/console doctrine:migrations:migrate -``` - -Now you have to update your crontab configuration by following this example: - -``` -0 * * * * /path/to/sylius/bin/console -e prod -q webgriffe:akeneo:import --all --importer="AttributeOptions" -* * * * * /path/to/sylius/bin/console -e prod -q webgriffe:akeneo:import --since-file=/path/to/sylius/var/storage/akeneo-import-sincefile.txt --importer="Product" --importer="ProductAssociations" -0 */6 * * * /path/to/sylius/bin/console -e prod -q webgriffe:akeneo:reconcile -``` - -If everything works well you have just completed your upgrade! Obviously, we suggest that you check the import of some products, -product associations and attribute options before considering the upgrade complete 😉. - -## Codebase - -### Use PHP 8 syntax ([#128](https://github.com/webgriffe/SyliusAkeneoPlugin/pull/128)) - -#### TL;DR -Refactored the codebase to use PHP 8 syntax. - -#### BC Breaks - -##### Changed - - [BC] The return type of Webgriffe\SyliusAkeneoPlugin\Converter\ValueConverterInterface#convert() changed from no type to array|bool|int|string - - [BC] The parameter $value of Webgriffe\SyliusAkeneoPlugin\Converter\ValueConverterInterface#convert() changed from no type to a non-contravariant array|bool|int|string - - [BC] The parameter $value of Webgriffe\SyliusAkeneoPlugin\Converter\ValueConverterInterface#convert() changed from no type to array|bool|int|string - - [BC] The parameter $value of Webgriffe\SyliusAkeneoPlugin\Converter\ValueConverter#convert() changed from no type to a non-contravariant array|bool|int|string - -### API client replacement ([#125](https://github.com/webgriffe/SyliusAkeneoPlugin/pull/125)) - -#### TL;DR -Removed our API Client interface in favor of the Akeneo PHP SDK client. - -#### BC Breaks - -##### Changed - - [BC] The parameter $apiClient of Webgriffe\SyliusAkeneoPlugin\AttributeOptions\Importer#__construct() changed from Webgriffe\SyliusAkeneoPlugin\AttributeOptions\ApiClientInterface to a non-contravariant Akeneo\Pim\ApiClient\AkeneoPimClientInterface - - [BC] The parameter $apiClient of Webgriffe\SyliusAkeneoPlugin\Converter\UnitMeasurementValueConverter#__construct() changed from Webgriffe\SyliusAkeneoPlugin\MeasurementFamiliesApiClientInterface to a non-contravariant Akeneo\Pim\ApiClient\AkeneoPimClientInterface - - [BC] The parameter $apiClient of Webgriffe\SyliusAkeneoPlugin\Product\Importer#__construct() changed from Webgriffe\SyliusAkeneoPlugin\ApiClientInterface to a non-contravariant Akeneo\Pim\ApiClient\AkeneoPimClientInterface - - [BC] The parameter $apiClient of Webgriffe\SyliusAkeneoPlugin\Product\ProductOptionsResolver#__construct() changed from Webgriffe\SyliusAkeneoPlugin\ApiClientInterface to a non-contravariant Akeneo\Pim\ApiClient\AkeneoPimClientInterface - - [BC] The parameter $apiClient of Webgriffe\SyliusAkeneoPlugin\ValueHandler\FileAttributeValueHandler#__construct() changed from Webgriffe\SyliusAkeneoPlugin\ApiClientInterface to a non-contravariant Akeneo\Pim\ApiClient\AkeneoPimClientInterface - - [BC] The parameter $apiClient of Webgriffe\SyliusAkeneoPlugin\ValueHandler\ImageValueHandler#__construct() changed from Webgriffe\SyliusAkeneoPlugin\ApiClientInterface to a non-contravariant Akeneo\Pim\ApiClient\AkeneoPimClientInterface - - [BC] The parameter $apiClient of Webgriffe\SyliusAkeneoPlugin\ValueHandler\ProductOptionValueHandler#__construct() changed from Webgriffe\SyliusAkeneoPlugin\ApiClientInterface to a non-contravariant Akeneo\Pim\ApiClient\AkeneoPimClientInterface - - [BC] The parameter $apiClient of Webgriffe\SyliusAkeneoPlugin\ProductAssociations\Importer#__construct() changed from Webgriffe\SyliusAkeneoPlugin\ApiClientInterface to a non-contravariant Akeneo\Pim\ApiClient\AkeneoPimClientInterface - -##### Removed - - [BC] Class Webgriffe\SyliusAkeneoPlugin\AttributeOptions\ApiClientInterface has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\ApiClientInterface has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\MeasurementFamiliesApiClientInterface has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\ApiClient has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\FamilyAwareApiClientInterface has been deleted - -### Remove deprecations ([#130](https://github.com/webgriffe/SyliusAkeneoPlugin/pull/130)) - -#### TL;DR -Removed all deprecations of the v1.x releases. - -#### BC Breaks - -##### Changed - - [BC] The number of required arguments for Webgriffe\SyliusAkeneoPlugin\Converter\ValueConverter#__construct() increased from 0 to 1 - - [BC] The parameter $translator of Webgriffe\SyliusAkeneoPlugin\Converter\ValueConverter#__construct() changed from Symfony\Contracts\Translation\TranslatorInterface|null to a non-contravariant Symfony\Contracts\Translation\TranslatorInterface - - [BC] The number of required arguments for Webgriffe\SyliusAkeneoPlugin\Product\Importer#__construct() increased from 12 to 13 - - [BC] The parameter $variantStatusResolver of Webgriffe\SyliusAkeneoPlugin\Product\Importer#__construct() changed from Webgriffe\SyliusAkeneoPlugin\Product\StatusResolverInterface|null to a non-contravariant Webgriffe\SyliusAkeneoPlugin\Product\StatusResolverInterface - - [BC] The number of required arguments for Webgriffe\SyliusAkeneoPlugin\ValueHandler\AttributeValueHandler#__construct() increased from 3 to 4 - - [BC] The parameter $valueConverter of Webgriffe\SyliusAkeneoPlugin\ValueHandler\AttributeValueHandler#__construct() changed from Webgriffe\SyliusAkeneoPlugin\Converter\ValueConverterInterface|null to a non-contravariant Webgriffe\SyliusAkeneoPlugin\Converter\ValueConverterInterface - - [BC] The number of required arguments for Webgriffe\SyliusAkeneoPlugin\ValueHandler\ChannelPricingValueHandler#__construct() increased from 4 to 5 - - [BC] The parameter $propertyAccessor of Webgriffe\SyliusAkeneoPlugin\ValueHandler\ChannelPricingValueHandler#__construct() changed from Symfony\Component\PropertyAccess\PropertyAccessorInterface|null to a non-contravariant Symfony\Component\PropertyAccess\PropertyAccessorInterface - - [BC] The number of required arguments for Webgriffe\SyliusAkeneoPlugin\ValueHandler\ProductOptionValueHandler#__construct() increased from 5 to 7 - - [BC] The parameter $translationLocaleProvider of Webgriffe\SyliusAkeneoPlugin\ValueHandler\ProductOptionValueHandler#__construct() changed from Sylius\Component\Resource\Translation\Provider\TranslationLocaleProviderInterface|null to a non-contravariant Sylius\Component\Resource\Translation\Provider\TranslationLocaleProviderInterface - - [BC] The parameter $translator of Webgriffe\SyliusAkeneoPlugin\ValueHandler\ProductOptionValueHandler#__construct() changed from Symfony\Contracts\Translation\TranslatorInterface|null to a non-contravariant Symfony\Contracts\Translation\TranslatorInterface - -##### Removed - - [BC] Property Webgriffe\SyliusAkeneoPlugin\DependencyInjection\WebgriffeSyliusAkeneoExtension::$valueHandlersTypesDefinitions was removed - -### Others ([#134](https://github.com/webgriffe/SyliusAkeneoPlugin/pull/134), [#147](https://github.com/webgriffe/SyliusAkeneoPlugin/pull/147), [#150](https://github.com/webgriffe/SyliusAkeneoPlugin/pull/150)) - -#### TL;DR - - The route `webgriffe_sylius_akeneo_product_enqueue` has been renamed in `webgriffe_sylius_akeneo_product_import`. - - The grid resource route `webgriffe_sylius_akeneo_admin_queue_item` has been removed. - - The grid template action `enqueueProduct` has been renamed in `importProduct`. - - The grid `webgriffe_sylius_akeneo_admin_queue_item` has been removed. - - The `sylius_admin_product` grid action `enqueue` has been renamed in `import`. - - A new `Webgriffe\SyliusAkeneoPlugin\Message\ItemImport` Symfony Messenger message has been added. - - The config `bind_arguments_by_name` under the `webgriffe_sylius_akeneo_plugin` has been removed. - - The config `resources` under the `webgriffe_sylius_akeneo_plugin` has been removed. - - Messages are changed, please view the new `translations/messages.en.yaml` file. - - The commands `webgriffe:akeneo:consume` and `webgriffe:akeneo:queue-cleanup` has been removed. - - The command `webgriffe:akeneo:enqueue` has been renamed to `webgriffe:akeneo:import`. - -#### BC Breaks - -##### Changed - - [BC] The number of required arguments for Webgriffe\SyliusAkeneoPlugin\ValueHandler\FileAttributeValueHandler#__construct() increased from 4 to 5 - - [BC] The parameter $akeneoAttributeCode of Webgriffe\SyliusAkeneoPlugin\ValueHandler\FileAttributeValueHandler#__construct() changed from string to a non-contravariant Webgriffe\SyliusAkeneoPlugin\TemporaryFilesManagerInterface - - [BC] The number of required arguments for Webgriffe\SyliusAkeneoPlugin\ValueHandler\ImageValueHandler#__construct() increased from 5 to 6 - - [BC] The parameter $akeneoAttributeCode of Webgriffe\SyliusAkeneoPlugin\ValueHandler\ImageValueHandler#__construct() changed from string to a non-contravariant Webgriffe\SyliusAkeneoPlugin\TemporaryFilesManagerInterface - -##### Removed - - [BC] Method Sylius\Bundle\ResourceBundle\DependencyInjection\Extension\AbstractResourceExtension#registerResources() was removed - - [BC] These ancestors of Webgriffe\SyliusAkeneoPlugin\DependencyInjection\WebgriffeSyliusAkeneoExtension have been removed: ["Sylius\\Bundle\\ResourceBundle\\DependencyInjection\\Extension\\AbstractResourceExtension"] - - [BC] Class Webgriffe\SyliusAkeneoPlugin\Menu\AdminMenuListener has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\EventSubscriber\CommandEventSubscriber has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\Controller\ProductEnqueueController has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\Doctrine\ORM\QueueItemRepository has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\Command\ConsumeCommand has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\Command\EnqueueCommand has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\Command\QueueCleanupCommand has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\Repository\CleanableQueueItemRepositoryInterface has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\Repository\QueueItemRepositoryInterface has been deleted - - [BC] Class Webgriffe\SyliusAkeneoPlugin\Entity\QueueItemInterface has been deleted - -### Test changes - -#### TL;DR -Edits made on test classes during the previous changes. - -#### BC Breaks - -##### Removed - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Behat\Page\Admin\QueueItem\IndexPage has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Behat\Page\Admin\QueueItem\IndexPageInterface has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Behat\Context\Setup\QueueContext has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Behat\Context\Db\QueueContext has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Behat\Context\Cli\QueueCleanupCommandContext has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Behat\Context\Cli\ConsumeCommandContext has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Behat\Context\Cli\EnqueueCommandContext has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Behat\Context\System\DateTimeContext has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Behat\Context\Transform\QueueItemContext has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Behat\Context\Ui\Admin\ManagingQueueItems has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Integration\DependencyInjection\CompilerPassTest has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Integration\DependencyInjection\ExtensionTest has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Integration\TestDouble\DateTimeBuilder has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Integration\TestDouble\ApiClientMock has been deleted - - [BC] Class Tests\Webgriffe\SyliusAkeneoPlugin\Integration\TemporaryFilesManagerTest has been deleted diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..abf75b2e --- /dev/null +++ b/docs/README.md @@ -0,0 +1,18 @@ +# just-the-docs-template + +## Building and previewing your site locally + +Assuming [Jekyll] and [Bundler] are installed on your computer: + +1. Change your working directory to the root directory of your site. + +2. Run `bundle install`. + +3. Run `bundle exec jekyll serve` to build your site and preview it at `localhost:4000`. + + The built site is stored in the directory `_site`. + +---- + +[Jekyll]: https://jekyllrb.com +[Bundler]: https://bundler.io diff --git a/docs/architecture_and_customization.md b/docs/architecture_and_customization.md new file mode 100644 index 00000000..b2d937ee --- /dev/null +++ b/docs/architecture_and_customization.md @@ -0,0 +1,180 @@ +--- +title: Architecture & customization +layout: page +nav_order: 5 +--- + +# Architecture & customization + +> This plugin makes use of [Symfony Messenger](https://symfony.com/doc/current/messenger.html) component. It is highly +> recommended to have a minimum knowledge of these component to understand how this integration works. + +This plugin has basically two entry points: + +* The UI admin import button, this will import only products +* The Import CLI command, this will import both product, product associations and attribute options + +Both this entry points deals to identify entities to import from Akeneo. When they have collected them they dispatch +an `Webgriffe\SyliusAkeneoPlugin\Message\ItemImport` message on the messenger default bus. +By default, in the configuration this message is handled by the main bus, the same bus used as default by Sylius for +catalog promotions. This means that, if you have configured the main bus to run synchronously the import will be +executed at the same time, otherwise it will be handled by the Messenger queue asynchronously. +We suggest to run it asynchronously especially if you plan to run the import command manually infrequently or with +option --all. + +To be able to import entities (or even only different parts of each entity), +the `Webgriffe\SyliusAkeneoPlugin\MessageHandler\ItemImportHandler` (the Messenger message handler) use an ** +importer registry** which holds all the registered **importers**. + +An importer is a service implementing the `Webgriffe\SyliusAkeneoPlugin\ImporterInterface` and that mainly holds the +logic about how to import its Akeneo entities. If you want to import from Akeneo other entities not implemented in this +plugin you have can implement your own importer. You can also replace an importer provided with this plugin by +decorating or replacing its service definition. + +To implement a new custom importer create a class which implements the `Webgriffe\SyliusAkeneoPlugin\ImporterInterface`: + +```php +// src/Importer/CustomImporter.php + +namespace App\Importer; + +use Webgriffe\SyliusAkeneoPlugin\ImporterInterface; + +final class CustomImporter implements ImporterInterface +{ + // ... +} +``` + +Then define the importer with the `webgriffe_sylius_akeneo.importer` tag: + +```yaml +# config/services.yaml + +app.custom.importer: + class: App\Importer\CustomImporter + tags: + - { name: 'webgriffe_sylius_akeneo.importer' } +``` + +Anyway, this plugin already implement the following importers. + +### Product Importer + +Akeneo is a PIM (Product Information Management) system so its job is to manage product data. For this reason, this +Sylius +Akeneo plugin is focused on importing products and provides a **product +importer** (`\Webgriffe\SyliusAkeneoPlugin\Product\Importer`). + +This product importer processes Akeneo product data through the following components: + +#### Taxons resolver + +A **taxons resolver** (`Webgriffe\SyliusAkeneoPlugin\Product\TaxonsResolverInterface`) which is responsible to return +the list of Sylius taxons for a given Akeneo product. The provided implementation of the taxons resolver is +the `Webgriffe\SyliusAkeneoPlugin\Product\AlreadyExistingTaxonsResolver` class which returns the already existent Sylius +taxons which have the same code as the related Akeneo categories. + +#### Product options resolver + +A **product options resolver** (`Webgriffe\SyliusAkeneoPlugin\Product\ProductOptionsResolverInterface`) which is +responsible to return the related Sylius's **product option(s)** when the product being imported is part of a parent +product model. The provided implementation of the product options resolver is +the `Webgriffe\SyliusAkeneoPlugin\Product\ProductOptionsResolver` class, which returns already existing product options +but also creates new ones if needed. + +#### Channels resolver + +A **channels resolver** (`Webgriffe\SyliusAkeneoPlugin\Product\ChannelsResolverInterface`) which is responsible to +return the list of Sylius channels where the products should be enabled. The provided implementation of the channels' +resolver is the `Webgriffe\SyliusAkeneoPlugin\Product\AllChannelsResolver` class which simply enables the product in all +available Sylius channels. + +#### Status resolver + +A **status resolver** (`Webgriffe\SyliusAkeneoPlugin\Product\StatusResolverInterface`) which is responsible to return +the Sylius product status (enabled or disabled, true or false). The provided implementation of the status resolver is +the `Webgriffe\SyliusAkeneoPlugin\Product\StatusResolver` which returns the same product status of the related Akeneo +product, but only if this doesn't belong to a parent product model, otherwise it will always return true (enabled). This +is because in Sylius the product status is at product level and not (also) at product variant level; instead, in Akeneo +the status is only at product level and not at product model level. So, in Akeneo, you could have only one disabled +product variant for a parent product which have several other variants enabled. This situation can't be mapped on Sylius +at present. + +#### Value handlers resolver + +A **value handlers resolver** (`Webgriffe\SyliusAkeneoPlugin\ValueHandlersResolverInterface`) which is responsible to +return a list of **value handlers** (`Webgriffe\SyliusAkeneoPlugin\ValueHandlerInterface`) for each Akeneo product +attribute value. + +The provided implementation of the value handlers resolver is +the `Webgriffe\SyliusAkeneoPlugin\PriorityValueHandlersResolver` which returns, for each attribute value, the list of +all the value handlers supporting that attribute value sorted by a priority. Each value handler returned by the resolver +for a given attribute is then called to handle that value. + +For more detail on how the Product importer works look at the code of +the `Webgriffe\SyliusAkeneoPlugin\Product\Importer::import()` method. + +#### Value handlers + +By default, the provided `Webgriffe\SyliusAkeneoPlugin\PriorityValueHandlersResolver` is configured with value handlers +specified in the `webgriffe_sylius_akeneo.value_handlers.product` array as explained in the configuration paragraph. +This plugin already provides some value handler implementations that are: + +* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\AttributeValueHandler` (type `generic_attribute`) it will automatically + handle Sylius attributes whose attribute code matches Akeneo attribute code. +* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\ChannelPricingValueHandler` (type `channel_pricing`): it sets the value + found on a given Akeneo price attribute (`options.$akeneoAttribute`) as the Sylius product's channels price or + original price for + channels whose base currency is the price currency of the Akeneo price. +* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\FileAttributeValueHandler` (type `file_attribute`): it saves the file + downloaded from the Akeneo file attribute (`options.$akeneoAttributeCode`) to the given destination + path (`options.$downloadPath`). +* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\GenericPropertyValueHandler` (type `generic_property`): using + the [Symfony's Property Access component](https://symfony.com/doc/current/components/property_access.html), it sets + the value found on a given Akeneo attribute (`options.$akeneoAttributeCode`) on a given property + path (`options.$propertyPath`) of both product and product variant. +* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\ImageValueHandler` (type `image`): it downloads the image found on a given + Akeneo image attribute (`options.$akeneoAttributeCode`) and sets it as a Sylius product image with a provided type + string (`options.$syliusImageType`). +* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\ImmutableSlugValueHandler` (type `immutable_slug`): it slugifies the value + found on a given Akeneo attribute (`options.$akeneoAttributeToSlugify`) and sets it on the Sylius slug product + translation property. +* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\MetricPropertyValueHandler` (type `metric_property`) using + the [Symfony's Property Access component](https://symfony.com/doc/current/components/property_access.html), it sets + the value found on a given Akeneo attribute (`options.$akeneoAttributeCode`) on a given property + path (`options.$propertyPath`) of both product and product variant. It automatically converts it to the default unit + of measurement or the one specified (`options.$akeneoUnitMeasurementCode`). +* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\ProductOptionValueHandler` (type `product_option`): it sets the value found + on a given Akeneo attribute as a Sylius product option value on the product variant. +* `Webgriffe\SyliusAkeneoPlugin\ValueHandler\TranslatablePropertyValueHandler` (type `translatable_property`): using + the [Symfony's Property Access component](https://symfony.com/doc/current/components/property_access.html), it sets + the value found on a given Akeneo attribute (`options.$akeneoAttributeCode`) on a given property + path (`options.$translationPropertyPath`) of both product and product variant translations. + +To add a custom value handler to the resolver you can implement your own by implementing +the `Webgriffe\SyliusAkeneoPlugin\ValueHandlerInterface` and then tag it with +the `webgriffe_sylius_akeneo.product.value_handler` tag: + +```yaml +# config/services.yaml + +app.my_custom_value_handler: + class: App\MyCustomValueHandler + tags: + - { name: 'webgriffe_sylius_akeneo.product.value_handler', priority: 42 } +``` + +### Product associations importer + +Another provided importer is the **product associations +importer** (`Webgriffe\SyliusAkeneoPlugin\ProductAssociations\Importer`). This importer imports the Akeneo products +associations to the corresponding Sylius products associations. The association types must already exist on Sylius with +the same code they have on Akeneo. + +### Attribute options importer + +Another provided importer is the **attribute options +importer** (`\Webgriffe\SyliusAkeneoPlugin\AttributeOptions\Importer`). This importer imports the Akeneo simple select +and multi select attributes options into Sylius select attributes. The select attributes must already exist on Sylius +with the same code they have on Akeneo. diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 00000000..3ed4c191 --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,27 @@ +--- +title: Configuration +layout: page +nav_order: 3 +--- + +# Configuration + +First you must configure your Akeneo API connection parameters. Edit +the `config/packages/webgriffe_sylius_akeneo_plugin.yaml` file by adding the following content: + +```yaml +# ... + +webgriffe_sylius_akeneo: + api_client: + # These values are from the official Akeneo PIM demo, replace with yours. + base_url: 'https://demo.akeneo.com/' + username: 'admin' + password: 'admin' + client_id: '1_demo_client_id' + secret: 'demo_secret' +``` + +Pay attention that among these parameters there are some sensitive configuration that you probably don't want to commit +in your VCS. There are different solutions to this problem, like env configurations and secrets. Refer +to [Symfony best practices doc](https://symfony.com/doc/current/best_practices.html#configuration) for more info. diff --git a/docs/Contributing.md b/docs/contributing.md similarity index 98% rename from docs/Contributing.md rename to docs/contributing.md index 49b50a0c..a3b15104 100644 --- a/docs/Contributing.md +++ b/docs/contributing.md @@ -1,3 +1,9 @@ +--- +title: Contributing +layout: page +nav_order: 6 +--- + # Contributing To contribute to this plugin clone this repository, create a branch for your feature or bugfix, do your changes and then @@ -162,7 +168,7 @@ bin/console app:taxa-import ``` Then create a new connection in Connect > Connection settings with type data destination and save the credentials in you .env.local. - + ```dotenv WEBGRIFFE_SYLIUS_AKENEO_PLUGIN_BASE_URL=http://localhost:8080/ WEBGRIFFE_SYLIUS_AKENEO_PLUGIN_CLIENT_ID=SAMPLE diff --git a/schedule-akeneo-import-button.png b/docs/images/schedule-akeneo-import-button.png similarity index 100% rename from schedule-akeneo-import-button.png rename to docs/images/schedule-akeneo-import-button.png diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..164a2867 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,35 @@ +--- +title: Home +layout: home +nav_order: 0 +--- + +# Webgriffe Sylius Akeneo plugin + +> **Please note!!**