diff --git a/features/export/ui/export_check_ids.feature b/features/export/ui/export_check_ids.feature index d72ee112..5339e5b2 100644 --- a/features/export/ui/export_check_ids.feature +++ b/features/export/ui/export_check_ids.feature @@ -9,9 +9,10 @@ Feature: Export links on Countries grid @ui Scenario: Exporting countries should export all of them - When I open the country admin index page - And I import country data from "countries.csv" csv file + Given I am on country import page + And I import data from "countries.csv" csv file Then I should see a notification that the import was successful + When I open the country admin index page And I should see 10 countries in the list Then I go to "/admin/export/sylius.country/csv" homepage And response should contain "Id,Code,Enabled" diff --git a/features/import/ui/importing_countries_from_csv.feature b/features/import/ui/importing_countries_from_csv.feature index 95cfa31b..fe401d30 100644 --- a/features/import/ui/importing_countries_from_csv.feature +++ b/features/import/ui/importing_countries_from_csv.feature @@ -10,9 +10,13 @@ Feature: Importing countries from csv @ui Scenario: Importing countries based on a valid csv-file When I open the country admin index page - And I import country data from "countries.csv" csv file + Then I should see an import button + When I click an import button + Then I should be on country import page + When I import data from "countries.csv" csv file Then I should see a notification that the import was successful - And I should see 10 countries in the list + When I open the country admin index page + Then I should see 10 countries in the list And I open the country admin index second page And I should see 3 countries in the list And the country "Andorra" should appear in the registry diff --git a/features/import/ui/importing_countries_from_excel.feature b/features/import/ui/importing_countries_from_excel.feature index d98b22a9..190aa837 100644 --- a/features/import/ui/importing_countries_from_excel.feature +++ b/features/import/ui/importing_countries_from_excel.feature @@ -10,9 +10,13 @@ Feature: Importing countries from excel @ui Scenario: Importing countries based on a valid excel-file When I open the country admin index page - And I import country data from "countries.xlsx" xlsx file + Then I should see an import button + When I click an import button + Then I should be on country import page + When I import data from "countries.xlsx" xlsx file Then I should see a notification that the import was successful - And I should see 10 countries in the list + When I open the country admin index page + Then I should see 10 countries in the list And I open the country admin index second page And I should see 3 countries in the list And the country "Andorra" should appear in the registry diff --git a/features/import/ui/importing_countries_from_json.feature b/features/import/ui/importing_countries_from_json.feature index 8ef682e3..c1300bcf 100644 --- a/features/import/ui/importing_countries_from_json.feature +++ b/features/import/ui/importing_countries_from_json.feature @@ -10,8 +10,12 @@ Feature: Importing countries from json @ui Scenario: Importing countries based on a valid json-file When I open the country admin index page - And I import country data from "countries.json" json file + Then I should see an import button + When I click an import button + Then I should be on country import page + When I import data from "countries.json" json file Then I should see a notification that the import was successful - And I should see 2 countries in the list + When I open the country admin index page + Then I should see 2 countries in the list And the country "Germany" should appear in the registry And the country "Switzerland" should appear in the registry diff --git a/features/import/ui/importing_customer_groups_from_csv.feature b/features/import/ui/importing_customer_groups_from_csv.feature index bf5fcca9..0319d8a0 100644 --- a/features/import/ui/importing_customer_groups_from_csv.feature +++ b/features/import/ui/importing_customer_groups_from_csv.feature @@ -9,8 +9,10 @@ Feature: Importing customer-groups from csv @ui Scenario: Importing customer-groups based on a valid csv-file - When I import customer-group data from "customer_groups.csv" csv file + Given I am on customer group import page + When I import data from "customer_groups.csv" csv file Then I should see a notification that the import was successful - And I should see 2 customer groups in the list + When I want to browse customer groups + Then I should see 2 customer groups in the list And I should see the customer group "premium" in the list And I should see the customer group "basic" in the list diff --git a/features/import/ui/importing_customer_groups_from_excel.feature b/features/import/ui/importing_customer_groups_from_excel.feature index 36b016ed..4292ece0 100644 --- a/features/import/ui/importing_customer_groups_from_excel.feature +++ b/features/import/ui/importing_customer_groups_from_excel.feature @@ -9,8 +9,10 @@ Feature: Importing customer-groups from excel @ui Scenario: Importing customer-groups based on a valid excel-file - When I import customer-group data from "customer_groups.xlsx" xlsx file + Given I am on customer group import page + When I import data from "customer_groups.xlsx" xlsx file Then I should see a notification that the import was successful - And I should see 2 customer groups in the list + When I want to browse customer groups + Then I should see 2 customer groups in the list And I should see the customer group "premium" in the list And I should see the customer group "basic" in the list diff --git a/features/import/ui/importing_customer_groups_from_json.feature b/features/import/ui/importing_customer_groups_from_json.feature index 2da23425..9b3a4dd5 100644 --- a/features/import/ui/importing_customer_groups_from_json.feature +++ b/features/import/ui/importing_customer_groups_from_json.feature @@ -9,8 +9,10 @@ Feature: Importing customer-groups from json @ui Scenario: Importing customer-groups based on a valid json-file - When I import customer-group data from "customer_groups.json" json file + Given I am on customer group import page + When I import data from "customer_groups.json" json file Then I should see a notification that the import was successful - And I should see 2 customer groups in the list + When I want to browse customer groups + Then I should see 2 customer groups in the list And I should see the customer group "premium" in the list And I should see the customer group "basic" in the list diff --git a/features/import/ui/importing_payment_methods_from_csv.feature b/features/import/ui/importing_payment_methods_from_csv.feature index 6046f57b..63dfd4c9 100644 --- a/features/import/ui/importing_payment_methods_from_csv.feature +++ b/features/import/ui/importing_payment_methods_from_csv.feature @@ -9,9 +9,10 @@ Feature: Importing payment methods from csv with the user interface @ui Scenario: Importing payment methods based on a valid csv-file - When I browse payment methods - And I import payment methods data from "payment-methods.csv" csv file + Given I am on payment method import page + When I import data from "payment-methods.csv" csv file Then I should see a notification that the import was successful - And I should see 2 payment methods in the list + When I browse payment methods + Then I should see 2 payment methods in the list And the payment method "Offline" should be in the registry And the payment method "PayPal" should be in the registry diff --git a/features/import/ui/importing_payment_methods_from_excel.feature b/features/import/ui/importing_payment_methods_from_excel.feature index da1b35ec..e4a8e664 100644 --- a/features/import/ui/importing_payment_methods_from_excel.feature +++ b/features/import/ui/importing_payment_methods_from_excel.feature @@ -9,9 +9,10 @@ Feature: Importing payment methods from excel with the user interface @ui Scenario: Importing payment methods based on a valid excel file - When I browse payment methods - And I import payment methods data from "payment-methods.xlsx" xlsx file + Given I am on payment method import page + When I import data from "payment-methods.xlsx" xlsx file Then I should see a notification that the import was successful - And I should see 2 payment methods in the list + When I browse payment methods + Then I should see 2 payment methods in the list And the payment method "Offline" should be in the registry And the payment method "PayPal" should be in the registry diff --git a/features/import/ui/importing_payment_methods_from_json.feature b/features/import/ui/importing_payment_methods_from_json.feature index 559f02c3..4c86dee9 100644 --- a/features/import/ui/importing_payment_methods_from_json.feature +++ b/features/import/ui/importing_payment_methods_from_json.feature @@ -9,9 +9,10 @@ Feature: Importing payment methods from json with the user interface @ui Scenario: Importing payment methods based on a valid json-file - When I browse payment methods - And I import payment methods data from "payment-methods.json" json file + Given I am on payment method import page + When I import data from "payment-methods.json" json file Then I should see a notification that the import was successful - And I should see 2 payment methods in the list + When I browse payment methods + Then I should see 2 payment methods in the list And the payment method "Offline" should be in the registry And the payment method "PayPal" should be in the registry diff --git a/features/import/ui/importing_products.feature b/features/import/ui/importing_products.feature index 775a632f..dacf9d1d 100644 --- a/features/import/ui/importing_products.feature +++ b/features/import/ui/importing_products.feature @@ -9,9 +9,10 @@ Feature: Import Products from grid @ui Scenario: Import products should create all of them - When I open the product admin index page - And I import product data from "products.csv" csv file + Given I am on product import page + And I import data from "products.csv" csv file Then I should see a notification that the import was successful - And I should see 2 products in the list + When I browse products + Then I should see 2 products in the list And the first product on the list should have name "Product 1" And the last product on the list should have name "Product 2" diff --git a/features/import/ui/importing_products_update.feature b/features/import/ui/importing_products_update.feature index db3a4d65..8dcb19cd 100644 --- a/features/import/ui/importing_products_update.feature +++ b/features/import/ui/importing_products_update.feature @@ -9,11 +9,12 @@ Feature: Import Products from grid @ui Scenario: Import products should update them - When I open the product admin index page - And I import product data from "products.csv" csv file + Given I am on product import page + And I import data from "products.csv" csv file Then I should see a notification that the import was successful - And I import product data from "products_update.csv" csv file + And I import data from "products_update.csv" csv file Then I should see a notification that the import was successful - And I should see 2 products in the list + When I browse products + Then I should see 2 products in the list And the first product on the list should have name "Product 1" And the last product on the list should have name "Product 2 update" diff --git a/features/import/ui/importing_products_with_attributes.feature b/features/import/ui/importing_products_with_attributes.feature index 6b4a4dc2..f46434b1 100644 --- a/features/import/ui/importing_products_with_attributes.feature +++ b/features/import/ui/importing_products_with_attributes.feature @@ -13,9 +13,10 @@ Feature: Import Products with attributes from grid @ui Scenario: Exporting products should export all of them - When I open the product admin index page - And I import product data from "products_attr.csv" csv file + Given I am on product import page + And I import data from "products_attr.csv" csv file Then I should see a notification that the import was successful - And I should see 2 products in the list + When I browse products + Then I should see 2 products in the list Then the product "Product 1" should appear in the registry And attribute "Attribute text" of product "Product 1" should be "Banana" in "en_US" diff --git a/features/import/ui/importing_tax_categories_from_csv.feature b/features/import/ui/importing_tax_categories_from_csv.feature index 8922fdde..6ba7ca1d 100644 --- a/features/import/ui/importing_tax_categories_from_csv.feature +++ b/features/import/ui/importing_tax_categories_from_csv.feature @@ -9,9 +9,10 @@ Feature: Importing tax categories from csv with the user interface @ui Scenario: Importing defined tax categories - When I browse all tax categories - And I import tax category data from "tax_categories.csv" csv file + Given I am on tax category import page + Then I import data from "tax_categories.csv" csv file Then I should see a notification that the import was successful - And I should see 2 tax categories in the list + When I browse all tax categories + Then I should see 2 tax categories in the list And the tax category "books" should appear in the registry And the tax category "cars" should appear in the registry diff --git a/features/import/ui/importing_tax_categories_from_excel.feature b/features/import/ui/importing_tax_categories_from_excel.feature index 2fca7c3a..451f06ca 100644 --- a/features/import/ui/importing_tax_categories_from_excel.feature +++ b/features/import/ui/importing_tax_categories_from_excel.feature @@ -9,9 +9,10 @@ Feature: Importing tax categories from excel with the user interface @ui Scenario: Importing defined tax categories - When I browse all tax categories - And I import tax category data from "tax_categories.xlsx" xlsx file + Given I am on tax category import page + When I import data from "tax_categories.xlsx" xlsx file Then I should see a notification that the import was successful - And I should see 2 tax categories in the list + When I browse all tax categories + Then I should see 2 tax categories in the list And the tax category "books" should appear in the registry And the tax category "cars" should appear in the registry diff --git a/features/import/ui/importing_tax_categories_from_json.feature b/features/import/ui/importing_tax_categories_from_json.feature index 8f143ec9..42e6dad3 100644 --- a/features/import/ui/importing_tax_categories_from_json.feature +++ b/features/import/ui/importing_tax_categories_from_json.feature @@ -9,9 +9,10 @@ Feature: Importing tax categories from json with the user interface @ui Scenario: Importing defined tax categories - When I browse all tax categories - And I import tax category data from "tax_categories.json" json file + Given I am on tax category import page + And I import data from "tax_categories.json" json file Then I should see a notification that the import was successful - And I should see 2 tax categories in the list + When I browse all tax categories + Then I should see 2 tax categories in the list And the tax category "books" should appear in the registry And the tax category "cars" should appear in the registry diff --git a/spec/Controller/ImportDataControllerSpec.php b/spec/Controller/ImportDataControllerSpec.php index dcd02391..8e179e3a 100644 --- a/spec/Controller/ImportDataControllerSpec.php +++ b/spec/Controller/ImportDataControllerSpec.php @@ -6,19 +6,25 @@ use FriendsOfSylius\SyliusImportExportPlugin\Controller\ImportDataController; use PhpSpec\ObjectBehavior; +use Sylius\Bundle\ResourceBundle\Controller\RequestConfigurationFactoryInterface; use Sylius\Component\Registry\ServiceRegistryInterface; +use Sylius\Component\Resource\Metadata\RegistryInterface; use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface; class ImportDataControllerSpec extends ObjectBehavior { function let( + RequestConfigurationFactoryInterface $configurationFactory, + RegistryInterface $resourceRegistry, ServiceRegistryInterface $registry, FlashBagInterface $flashBag, FormFactoryInterface $formFactory, \Twig_Environment $twig ) { $this->beConstructedWith( + $configurationFactory, + $resourceRegistry, $registry, $flashBag, $formFactory, diff --git a/spec/DependencyInjection/Compiler/RegisterImporterPassSpec.php b/spec/DependencyInjection/Compiler/RegisterImporterPassSpec.php index 915127af..0580279d 100644 --- a/spec/DependencyInjection/Compiler/RegisterImporterPassSpec.php +++ b/spec/DependencyInjection/Compiler/RegisterImporterPassSpec.php @@ -5,9 +5,9 @@ namespace spec\FriendsOfSylius\SyliusImportExportPlugin\DependencyInjection\Compiler; use FriendsOfSylius\SyliusImportExportPlugin\DependencyInjection\Compiler\RegisterImporterPass; +use FriendsOfSylius\SyliusImportExportPlugin\Listener\ImportButtonGridListener; use PhpSpec\ObjectBehavior; use Prophecy\Argument; -use Sylius\Bundle\UiBundle\Block\BlockEventListener; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; @@ -27,7 +27,7 @@ function it_is_initializable() function it_processes_the_importer_services( ContainerBuilder $container, Definition $importerRegistry, - Definition $blockEventDefinition + Definition $importButtonListenerDefinition ) { $importerType = 'csv'; /** @@ -47,8 +47,8 @@ function it_processes_the_importer_services( ]); $container->register( Argument::type('string'), - BlockEventListener::class - )->willReturn($blockEventDefinition)->shouldBeCalled(); + ImportButtonGridListener::class + )->willReturn($importButtonListenerDefinition)->shouldBeCalled(); /** * prepare the mock for the importerRegistry @@ -61,23 +61,23 @@ function it_processes_the_importer_services( /** * prepare the mock for the definition of the sonata-event */ - $blockEventDefinition->setAutowired(false) + $importButtonListenerDefinition->setAutowired(false) ->shouldBeCalled() - ->willReturn($blockEventDefinition); + ->willReturn($importButtonListenerDefinition); - $blockEventDefinition->addArgument(Argument::type('string')) + $importButtonListenerDefinition->addArgument(Argument::type('string')) ->shouldBeCalled() - ->willReturn($blockEventDefinition); + ->willReturn($importButtonListenerDefinition); - $blockEventDefinition->addTag( - 'kernel.event_listener', + $importButtonListenerDefinition->addTag( + 'kernel.event_listener', [ - 'event' => 'sonata.block.event.sylius.admin.' . $importerType . '.index.after_content', - 'method' => 'onBlockEvent', + 'event' => 'sylius.grid.admin_' . $importerType, + 'method' => 'onSyliusGridAdmin', ] - ) + ) ->shouldBeCalled() - ->willReturn($blockEventDefinition); + ->willReturn($importButtonListenerDefinition); /** * run the test diff --git a/src/Controller/ImportDataController.php b/src/Controller/ImportDataController.php index 2ca6e360..354a175c 100644 --- a/src/Controller/ImportDataController.php +++ b/src/Controller/ImportDataController.php @@ -9,17 +9,24 @@ use FriendsOfSylius\SyliusImportExportPlugin\Importer\ImporterInterface; use FriendsOfSylius\SyliusImportExportPlugin\Importer\ImporterRegistry; use FriendsOfSylius\SyliusImportExportPlugin\Importer\ImporterResult; +use Sylius\Bundle\ResourceBundle\Controller\RequestConfigurationFactoryInterface; use Sylius\Component\Registry\ServiceRegistryInterface; +use Sylius\Component\Resource\Metadata\RegistryInterface; use Symfony\Component\Form\FormFactoryInterface; -use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\File\UploadedFile; -use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface; +use Twig\Environment; final class ImportDataController { + /** @var RequestConfigurationFactoryInterface */ + private $configurationFactory; + + /** @var RegistryInterface */ + private $resourceRegistry; + /** @var FlashBagInterface */ private $flashBag; @@ -33,78 +40,60 @@ final class ImportDataController private $twig; public function __construct( + RequestConfigurationFactoryInterface $configurationFactory, + RegistryInterface $resourceRegistry, ServiceRegistryInterface $registry, FlashBagInterface $flashBag, FormFactoryInterface $formFactory, - \Twig_Environment $twig + Environment $twig ) { + $this->configurationFactory = $configurationFactory; + $this->resourceRegistry = $resourceRegistry; $this->registry = $registry; $this->formFactory = $formFactory; $this->twig = $twig; $this->flashBag = $flashBag; } - public function importFormAction(Request $request): Response + public function importAction(Request $request, string $resource): Response { - $importer = $request->attributes->get('resource'); - $form = $this->getForm($importer); - - $content = $this->twig->render( - '@FOSSyliusImportExportPlugin/Crud/import_form.html.twig', - ['form' => $form->createView(), 'resource' => $importer] - ); - - return new Response($content); - } + $configuration = $this->configurationFactory->create($this->resourceRegistry->get($resource), $request); - public function importAction(Request $request): RedirectResponse - { - $importer = $request->attributes->get('resource'); - $form = $this->getForm($importer); + $form = $this->formFactory->create(ImportType::class, null, ['importer_type' => $resource]); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { try { - $this->importData($importer, $form); + $this->import( + $resource, + $form->get('format')->getData(), + $form->get('file')->getData() + ); } catch (\Throwable $exception) { $this->flashBag->add('error', $exception->getMessage()); } } - $referer = $request->headers->get('referer'); - return new RedirectResponse($referer); - } - - private function getForm(string $importerType): FormInterface - { - return $this->formFactory->create(ImportType::class, null, ['importer_type' => $importerType]); + return new Response( + $this->twig->render( + '@FOSSyliusImportExportPlugin/import.html.twig', + [ + 'form' => $form->createView(), + 'resource' => $resource, + 'configuration' => $configuration, + 'metadata' => $configuration->getMetadata(), + ] + ) + ); } - private function importData(string $importer, FormInterface $form): void + private function import(string $type, string $format, UploadedFile $file): void { - $format = $form->get('format')->getData(); - $name = ImporterRegistry::buildServiceName($importer, $format); - if (!$this->registry->has($name)) { - $message = sprintf("No importer found of type '%s' for format '%s'", $importer, $format); - - throw new ImporterException($message); - } - - /** @var UploadedFile|null $file */ - $file = $form->get('import-data')->getData(); + $name = ImporterRegistry::buildServiceName($type, $format); /** @var ImporterInterface $service */ $service = $this->registry->get($name); - - if (null === $file) { - throw new ImporterException('No file selected'); - } - + /** @var string $path */ $path = $file->getRealPath(); - - if (false === $path) { - throw new ImporterException(sprintf('File %s could not be loaded', $file->getClientOriginalName())); - } - /** @var ImporterResult $result */ $result = $service->import($path); diff --git a/src/DependencyInjection/Compiler/RegisterImporterPass.php b/src/DependencyInjection/Compiler/RegisterImporterPass.php index 90e3430c..5ac70070 100644 --- a/src/DependencyInjection/Compiler/RegisterImporterPass.php +++ b/src/DependencyInjection/Compiler/RegisterImporterPass.php @@ -5,7 +5,7 @@ namespace FriendsOfSylius\SyliusImportExportPlugin\DependencyInjection\Compiler; use FriendsOfSylius\SyliusImportExportPlugin\Importer\ImporterRegistry; -use Sylius\Bundle\UiBundle\Block\BlockEventListener; +use FriendsOfSylius\SyliusImportExportPlugin\Listener\ImportButtonGridListener; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; @@ -17,6 +17,7 @@ final class RegisterImporterPass implements CompilerPassInterface */ public function process(ContainerBuilder $container): void { + $typesWithImportButton = []; $serviceId = 'sylius.importers_registry'; if ($container->has($serviceId) == false) { return; @@ -37,34 +38,40 @@ public function process(ContainerBuilder $container): void $importersRegistry->addMethodCall('register', [$name, new Reference($id)]); - if ($container->getParameter('sylius.importer.web_ui')) { - $this->registerImportFormBlockEvent($container, $type); + if ($container->getParameter('sylius.importer.web_ui') && !in_array($type, $typesWithImportButton)) { + $typesWithImportButton[] = $type; + $this->registerEventListenerForImportButton($container, $type); } } } - private function registerImportFormBlockEvent(ContainerBuilder $container, string $type): void + private function registerEventListenerForImportButton(ContainerBuilder $container, string $type): void { - $eventHookName = ImporterRegistry::buildEventHookName($type) . '.import'; + $serviceId = sprintf('fos_import_export.event_listener.%s_grid.import_button', $type); - if ($container->has($eventHookName)) { + if ($container->has($serviceId)) { return; } $container - ->register( - $eventHookName, - BlockEventListener::class - ) + ->register($serviceId, ImportButtonGridListener::class) ->setAutowired(false) - ->addArgument('@FOSSyliusImportExportPlugin/Crud/import.html.twig') + ->addArgument($type) ->addTag( 'kernel.event_listener', [ - 'event' => 'sonata.block.event.sylius.admin.' . $type . '.index.after_content', - 'method' => 'onBlockEvent', + 'event' => $this->getEventName($type), + 'method' => 'onSyliusGridAdmin', ] - ) - ; + ); + } + + private function getEventName(string $type): string + { + if (strpos($type, '.') !== false) { + $type = substr($type, strpos($type, '.') + 1); + } + + return 'sylius.grid.admin_' . $type; } } diff --git a/src/Form/ImportType.php b/src/Form/ImportType.php index 7799feff..e49d6497 100644 --- a/src/Form/ImportType.php +++ b/src/Form/ImportType.php @@ -8,8 +8,13 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\FileType; +use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Validator\Constraints\Callback; +use Symfony\Component\Validator\Constraints\EqualTo; +use Symfony\Component\Validator\Constraints\NotBlank; +use Symfony\Component\Validator\Context\ExecutionContextInterface; class ImportType extends AbstractType { @@ -21,28 +26,53 @@ public function __construct(ImporterRegistry $importerRegistry) $this->importerRegistry = $importerRegistry; } - public function configureOptions(OptionsResolver $resolver): void - { - $resolver->setRequired('importer_type'); - $resolver->setAllowedTypes('importer_type', 'string'); - } - public function buildForm(FormBuilderInterface $builder, array $options): void { $builder + ->add('type', HiddenType::class, [ + 'required' => true, + 'data' => $options['importer_type'], + 'constraints' => [ + new EqualTo(['value' => $options['importer_type']]), + ], + ]) ->add('format', ChoiceType::class, [ 'choices' => $this->buildChoices($options), 'expanded' => false, 'multiple' => false, 'required' => true, ]) - ->add('import-data', FileType::class, [ + ->add('file', FileType::class, [ 'required' => true, - 'block_name' => 'import_data', + 'constraints' => [ + new NotBlank(), + ], ]) ; } + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setRequired('importer_type'); + $resolver->setAllowedTypes('importer_type', 'string'); + $resolver->setDefault('constraints', [ + new Callback([$this, 'validate']), + ]); + } + + public function validate($data, ExecutionContextInterface $context) + { + if ($context->getViolations()->count() > 0 || empty($data['type']) || empty($data['format'])) { + return; + } + + $name = ImporterRegistry::buildServiceName($data['type'], $data['format']); + if (!$this->importerRegistry->has($name)) { + $message = sprintf("No importer found of type '%s' for format '%s'", $data['type'], $data['format']); + $context->addViolation($message); + } + } + private function buildChoices(array $options): array { /** @var string $importerType */ diff --git a/src/Importer/ImporterRegistry.php b/src/Importer/ImporterRegistry.php index e1718e76..84c358bc 100644 --- a/src/Importer/ImporterRegistry.php +++ b/src/Importer/ImporterRegistry.php @@ -12,11 +12,10 @@ class ImporterRegistry extends ServiceRegistry public static function buildServiceName(string $type, string $format): string { - return sprintf('%s.%s', $type, $format); - } + if (strpos($type, '.') === false) { + $type = 'sylius.' . $type; + } - public static function buildEventHookName(string $type): string - { - return sprintf('%s_%s', self::EVENT_HOOK_NAME_PREFIX_ADMIN_CRUD_AFTER_CONTENT, $type); + return sprintf('%s.%s', $type, $format); } } diff --git a/src/Listener/ImportButtonGridListener.php b/src/Listener/ImportButtonGridListener.php new file mode 100644 index 00000000..26ded437 --- /dev/null +++ b/src/Listener/ImportButtonGridListener.php @@ -0,0 +1,47 @@ +resource = $resource; + } + + public function onSyliusGridAdmin(GridDefinitionConverterEvent $event): void + { + $grid = $event->getGrid(); + + if (!$grid->hasActionGroup('main')) { + $grid->addActionGroup(ActionGroup::named('main')); + } + + $actionGroup = $grid->getActionGroup('main'); + + if ($actionGroup->hasAction('import')) { + return; + } + + $action = Action::fromNameAndType('import', 'default'); + $action->setLabel('fos.import_export.ui.import'); + $action->setIcon('upload'); + $action->setOptions([ + 'link' => [ + 'route' => 'fos_sylius_import_export_import_data', + 'parameters' => ['resource' => $this->resource], + ], + ]); + + $actionGroup->addAction($action); + } +} diff --git a/src/Resources/config/routing.yml b/src/Resources/config/routing.yml index 8686226b..fd736765 100644 --- a/src/Resources/config/routing.yml +++ b/src/Resources/config/routing.yml @@ -1,9 +1,12 @@ ## Import route -app_import_data: +fos_sylius_import_export_import_data: path: /import/{resource} - methods: [POST] + methods: [GET, POST] defaults: _controller: sylius.controller.import_data:importAction + _sylius: + section: admin + permission: true ## Export routes for specific settings app_export_data_country: diff --git a/src/Resources/config/services.yml b/src/Resources/config/services.yml index 35102a08..8880df0e 100644 --- a/src/Resources/config/services.yml +++ b/src/Resources/config/services.yml @@ -10,6 +10,8 @@ services: public: true class: FriendsOfSylius\SyliusImportExportPlugin\Controller\ImportDataController arguments: + - "@sylius.resource_controller.request_configuration_factory" + - "@sylius.resource_registry" - "@sylius.importers_registry" - "@session.flash_bag" - "@form.factory" diff --git a/src/Resources/config/services_import_csv.yml b/src/Resources/config/services_import_csv.yml index dadf5ebf..222a702c 100644 --- a/src/Resources/config/services_import_csv.yml +++ b/src/Resources/config/services_import_csv.yml @@ -16,7 +16,7 @@ services: - "%sylius.importer.fail_on_incomplete%" - "%sylius.importer.stop_on_failure%" tags: - - { name: sylius.importer, type: country, format: csv } + - { name: sylius.importer, type: sylius.country, format: csv } sylius.importer.customer_group.csv: class: FriendsOfSylius\SyliusImportExportPlugin\Importer\ResourceImporter @@ -29,7 +29,7 @@ services: - "%sylius.importer.fail_on_incomplete%" - "%sylius.importer.stop_on_failure%" tags: - - { name: sylius.importer, type: customer_group, format: csv } + - { name: sylius.importer, type: sylius.customer_group, format: csv } sylius.importer.payment_methods.csv: class: FriendsOfSylius\SyliusImportExportPlugin\Importer\ResourceImporter @@ -42,7 +42,7 @@ services: - "%sylius.importer.fail_on_incomplete%" - "%sylius.importer.stop_on_failure%" tags: - - { name: sylius.importer, type: payment_method, format: csv } + - { name: sylius.importer, type: sylius.payment_method, format: csv } sylius.importer.tax_categories.csv: class: FriendsOfSylius\SyliusImportExportPlugin\Importer\ResourceImporter @@ -55,7 +55,7 @@ services: - "%sylius.importer.fail_on_incomplete%" - "%sylius.importer.stop_on_failure%" tags: - - { name: sylius.importer, type: tax_category, format: csv } + - { name: sylius.importer, type: sylius.tax_category, format: csv } sylius.importer.products.csv: class: FriendsOfSylius\SyliusImportExportPlugin\Importer\ResourceImporter @@ -68,4 +68,4 @@ services: - "%sylius.importer.fail_on_incomplete%" - "%sylius.importer.stop_on_failure%" tags: - - { name: sylius.importer, type: product, format: csv } + - { name: sylius.importer, type: sylius.product, format: csv } diff --git a/src/Resources/config/services_import_json.yml b/src/Resources/config/services_import_json.yml index 2074156c..98da5006 100644 --- a/src/Resources/config/services_import_json.yml +++ b/src/Resources/config/services_import_json.yml @@ -10,7 +10,7 @@ services: - "%sylius.importer.fail_on_incomplete%" - "%sylius.importer.stop_on_failure%" tags: - - { name: sylius.importer, type: country, format: json } + - { name: sylius.importer, type: sylius.country, format: json } sylius.importer.customer_group.json: class: FriendsOfSylius\SyliusImportExportPlugin\Importer\JsonResourceImporter @@ -22,7 +22,7 @@ services: - "%sylius.importer.fail_on_incomplete%" - "%sylius.importer.stop_on_failure%" tags: - - { name: sylius.importer, type: customer_group, format: json } + - { name: sylius.importer, type: sylius.customer_group, format: json } sylius.importer.payment_methods.json: class: FriendsOfSylius\SyliusImportExportPlugin\Importer\JsonResourceImporter @@ -34,7 +34,7 @@ services: - "%sylius.importer.fail_on_incomplete%" - "%sylius.importer.stop_on_failure%" tags: - - { name: sylius.importer, type: payment_method, format: json } + - { name: sylius.importer, type: sylius.payment_method, format: json } sylius.importer.tax_categories.json: class: FriendsOfSylius\SyliusImportExportPlugin\Importer\JsonResourceImporter @@ -46,7 +46,7 @@ services: - "%sylius.importer.fail_on_incomplete%" - "%sylius.importer.stop_on_failure%" tags: - - { name: sylius.importer, type: tax_category, format: json } + - { name: sylius.importer, type: sylius.tax_category, format: json } sylius.importer.customers.json: @@ -59,4 +59,4 @@ services: - "%sylius.importer.fail_on_incomplete%" - "%sylius.importer.stop_on_failure%" tags: - - { name: sylius.importer, type: customer, format: json } + - { name: sylius.importer, type: sylius.customer, format: json } diff --git a/src/Resources/config/services_import_spreadsheet.yml b/src/Resources/config/services_import_spreadsheet.yml index b77ed009..32580147 100644 --- a/src/Resources/config/services_import_spreadsheet.yml +++ b/src/Resources/config/services_import_spreadsheet.yml @@ -16,7 +16,7 @@ services: - "%sylius.importer.fail_on_incomplete%" - "%sylius.importer.stop_on_failure%" tags: - - { name: sylius.importer, type: country, format: xlsx } + - { name: sylius.importer, type: sylius.country, format: xlsx } sylius.importer.customer_group.xlsx: class: FriendsOfSylius\SyliusImportExportPlugin\Importer\ResourceImporter @@ -29,7 +29,7 @@ services: - "%sylius.importer.fail_on_incomplete%" - "%sylius.importer.stop_on_failure%" tags: - - { name: sylius.importer, type: customer_group, format: xlsx } + - { name: sylius.importer, type: sylius.customer_group, format: xlsx } sylius.importer.payment_methods.xlsx: class: FriendsOfSylius\SyliusImportExportPlugin\Importer\ResourceImporter @@ -42,7 +42,7 @@ services: - "%sylius.importer.fail_on_incomplete%" - "%sylius.importer.stop_on_failure%" tags: - - { name: sylius.importer, type: payment_method, format: xlsx } + - { name: sylius.importer, type: sylius.payment_method, format: xlsx } sylius.importer.tax_categories.xlsx: class: FriendsOfSylius\SyliusImportExportPlugin\Importer\ResourceImporter @@ -55,4 +55,4 @@ services: - "%sylius.importer.fail_on_incomplete%" - "%sylius.importer.stop_on_failure%" tags: - - { name: sylius.importer, type: tax_category, format: xlsx } + - { name: sylius.importer, type: sylius.tax_category, format: xlsx } diff --git a/src/Resources/views/Crud/_breadcrumb.html.twig b/src/Resources/views/Crud/_breadcrumb.html.twig new file mode 100644 index 00000000..83047af3 --- /dev/null +++ b/src/Resources/views/Crud/_breadcrumb.html.twig @@ -0,0 +1,16 @@ +{% import '@SyliusAdmin/Macro/breadcrumb.html.twig' as breadcrumb %} + +{% set index_url = path( + configuration.vars.index.route.name|default(configuration.getRouteName('index')), + configuration.vars.index.route.parameters|default(configuration.vars.route.parameters|default({})) + ) +%} + +{% set breadcrumbs = [ + { label: 'sylius.ui.administration'|trans, url: path('sylius_admin_dashboard') }, + { label: (metadata.applicationName~'.ui.'~metadata.pluralName)|trans, url: index_url }, + { label: 'fos.import_export.ui.import'|trans } + ] +%} + +{{ breadcrumb.crumble(breadcrumbs) }} diff --git a/src/Resources/views/Crud/_content.html.twig b/src/Resources/views/Crud/_content.html.twig new file mode 100644 index 00000000..8ef31d09 --- /dev/null +++ b/src/Resources/views/Crud/_content.html.twig @@ -0,0 +1,34 @@ +{% form_theme form '@FOSSyliusImportExportPlugin/Form/theme.html.twig' %} + +{% set index_url = path( + configuration.vars.index.route.name|default(configuration.getRouteName('index')), + configuration.vars.index.route.parameters|default(configuration.vars.route.parameters|default({})) + ) +%} + +