From d2e20295fe4ee96311b1dd7cbfb87ab202bdbe44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20B=C3=A4hr?= Date: Wed, 27 Sep 2023 17:50:46 +0200 Subject: [PATCH] init --- .github/workflows/ci.yml | 34 +++ .gitignore | 42 ++++ README.md | 14 +- codeception.yml | 40 ++++ composer.json | 69 ++++++ phpcs.xml | 56 +++++ phpmd-ruleset.xml | 35 +++ phpstan-bootstrap.php | 38 ++++ phpstan.neon | 23 ++ .../NavigationGeneratorConstants.php | 12 ++ .../Model/NavigationNodeFileGenerator.php | 200 ++++++++++++++++++ .../NavigationGeneratorBusinessFactory.php | 55 +++++ .../Business/NavigationGeneratorFacade.php | 21 ++ .../NavigationGeneratorFacadeInterface.php | 13 ++ .../Console/NavigationGeneratorConsole.php | 40 ++++ .../NavigationGeneratorConfig.php | 35 +++ .../NavigationGeneratorDependencyProvider.php | 75 +++++++ tests/ValanticSprykerTest/.gitkeep | 0 tests/_bootstrap.php | 11 + 19 files changed, 812 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .gitignore create mode 100644 codeception.yml create mode 100644 composer.json create mode 100644 phpcs.xml create mode 100644 phpmd-ruleset.xml create mode 100644 phpstan-bootstrap.php create mode 100644 phpstan.neon create mode 100644 src/ValanticSpryker/Shared/NavigationGenerator/NavigationGeneratorConstants.php create mode 100644 src/ValanticSpryker/Zed/NavigationGenerator/Business/Model/NavigationNodeFileGenerator.php create mode 100644 src/ValanticSpryker/Zed/NavigationGenerator/Business/NavigationGeneratorBusinessFactory.php create mode 100644 src/ValanticSpryker/Zed/NavigationGenerator/Business/NavigationGeneratorFacade.php create mode 100644 src/ValanticSpryker/Zed/NavigationGenerator/Business/NavigationGeneratorFacadeInterface.php create mode 100644 src/ValanticSpryker/Zed/NavigationGenerator/Communication/Console/NavigationGeneratorConsole.php create mode 100644 src/ValanticSpryker/Zed/NavigationGenerator/NavigationGeneratorConfig.php create mode 100644 src/ValanticSpryker/Zed/NavigationGenerator/NavigationGeneratorDependencyProvider.php create mode 100644 tests/ValanticSprykerTest/.gitkeep create mode 100644 tests/_bootstrap.php diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..199372a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,34 @@ +name: Continuous Integration + +on: [push] + +jobs: + analyse: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up PHP environment + uses: shivammathur/setup-php@v2 + with: + php-version: '8.1' + + - name: Validate composer.json + run: composer validate + + - name: Install dependencies + run: composer install + + - name: Run tests + run: composer test + + - name: Check coding standards + run: composer cs-check + + - name: Check static analysis (PHPStan) + run: composer stan + + - name: Check messdetector + run: composer md-check diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2b57c4f --- /dev/null +++ b/.gitignore @@ -0,0 +1,42 @@ +# IDE +.idea/ +.project/ +nbproject/ +.buildpath/ +.settings/ +*.sublime-* +src/Generated/* +src/Orm/* + +# OS +.DS_Store +*.AppleDouble +*.AppleDB +*.AppleDesktop + +# grunt stuff +.grunt +.sass-cache +/node_modules/ + +# tooling +vendor/ +composer.lock +auth.json +.phpunit.result.cache + +# built client resources +src/*/Zed/*/Static/Public +src/*/Zed/*/Static/Assets/sprite + +# Propel classes +src/*/Zed/*/Persistence/Propel/Base/* +src/*/Zed/*/Persistence/Propel/Map/* + +# tests +tests/**/_generated/ +tests/_output/* +!tests/_output/.gitkeep +tests/app/* +src/Orm +src/Generated \ No newline at end of file diff --git a/README.md b/README.md index c6b8ec3..334297f 100644 --- a/README.md +++ b/README.md @@ -1 +1,13 @@ -# navigation-generator \ No newline at end of file +# Navigation Generator + +## Description: +Adds new console command to spryker, which uses the imported category data to generate a navigation_node.csv based on the category-tree. + +## Usage: +``` +vendor/bin/console data:generate:navigation-node +``` +### Configuration: +* `NavigationGeneratorConstants::OUTPUT_PATH` (Default: `APPLICATION_ROOT_DIR . '/data/import/common/common/navigation_node.csv'`) +* `NavigationGeneratorConstants::FALLBACK_LOCALE` (Default: `de_DE`, is used when for a configured locale no category data is available) +* `NavigationGeneratorConstants::NAVIGATION_KEY` (Default: `MAIN_NAVIGATION`) diff --git a/codeception.yml b/codeception.yml new file mode 100644 index 0000000..cb3e967 --- /dev/null +++ b/codeception.yml @@ -0,0 +1,40 @@ +namespace: ValanticSpryker + +suites: + unit: + path: . + +settings: + shuffle: true + lint: true + +bootstrap: _bootstrap.php + +paths: + tests: tests + output: tests/_output + support: tests/_support + data: tests/_data + +coverage: + enabled: true + include: + - src/ValanticSpryker/*.php + +modules: + enabled: + - \FondOfCodeception\Module\Spryker + config: + \FondOfCodeception\Module\Spryker: + generate_transfer: false + generate_map_classes: false + generate_propel_classes: false + +env: + standalone: + modules: + config: + \FondOfCodeception\Module\Spryker: + generate_transfer: true + generate_map_classes: true + generate_propel_classes: true diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..ee945b4 --- /dev/null +++ b/composer.json @@ -0,0 +1,69 @@ +{ + "name": "valantic-spryker/navigation-generator", + "type": "library", + "description": "Generates navigation-node.csv based on imported category data", + "require": { + "php": ">=8.0", + "spryker/kernel": "^3.0.0", + "spryker/store": "^1.0.0", + "spryker/category": "^5.0.0", + "spryker/category-storage": "^2.1.1" + }, + "autoload": { + "psr-4": { + "ValanticSpryker\\": "src/ValanticSpryker/" + } + }, + "autoload-dev": { + "psr-4": { + "ValanticSprykerTest\\": "tests/ValanticSprykerTest/", + "Generated\\": "src/Generated/", + "Orm\\Zed\\": "src/Orm/Zed/" + } + }, + "minimum-stability": "dev", + "prefer-stable": true, + "config": { + "platform": { + "php": "8.0.19" + }, + "preferred-install": "dist", + "use-include-path": true, + "sort-packages": true, + "github-protocols": [ + "https" + ], + "process-timeout": 900, + "chromium-revision": 814168, + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } + }, + "authors": [ + { + "name": "Valantic", + "homepage": "https://www.valantic.com" + } + ], + "keywords": [ + "spryker" + ], + "include-path": [ + "src/" + ], + "require-dev": { + "fond-of-codeception/spryker": "^1.0 || ^2.0", + "spryker-sdk/phpstan-spryker": "*", + "spryker/architecture-sniffer": "*", + "spryker/code-sniffer": "*", + "spryker/development": "*", + "spryker/testify": "*" + }, + "scripts": { + "cs-fix": "phpcbf --standard=phpcs.xml src", + "cs-check": "phpcs -s --standard=phpcs.xml --report=full src", + "md-check": "phpmd src/ text phpmd-ruleset.xml --minimumpriority 2", + "stan": "php -d memory_limit=3072M vendor/bin/phpstan analyze -l 4 src/ValanticSpryker/", + "test": "codecept run --env standalone --coverage-text --no-colors --coverage-html" + } +} diff --git a/phpcs.xml b/phpcs.xml new file mode 100644 index 0000000..057c8c3 --- /dev/null +++ b/phpcs.xml @@ -0,0 +1,56 @@ + + + + Spryker Coding Standard for Project. + + Extends main Spryker Coding Standard. + All sniffs in ./Sniffs will be auto loaded + + + + + + + + + + + + + + + + + + + + + + */src/Generated/* + */src/Orm/* + */tests/_support/_generated/* + */tests/*/_support/_generated/* + */tests/*/_support/*Tester.php + */tests/_helpers/* + */tests/_output/* + ./data/DE/* + ./data/AT/* + ./data/SH/* + ./data/PZ/* + ./data/US/* + ./public + */node_modules/* + */vendor/* + + + + + + + + + + + + + diff --git a/phpmd-ruleset.xml b/phpmd-ruleset.xml new file mode 100644 index 0000000..e1767f8 --- /dev/null +++ b/phpmd-ruleset.xml @@ -0,0 +1,35 @@ + + + + Extends Spryker's PHP Mess Detector Rule Set + + + tests/_data + tests/_output + tests/_support + */Persistence/Base/* + */Persistence/Map/* + */Orm/Propel/* + */Generated/* + *Zed/DataImport/* + + + + + + + + + + + + + + + + + diff --git a/phpstan-bootstrap.php b/phpstan-bootstrap.php new file mode 100644 index 0000000..1abd04d --- /dev/null +++ b/phpstan-bootstrap.php @@ -0,0 +1,38 @@ +locales = $this->getLocales(); + } + + /** + * @return void + */ + public function generateNavigationNodeFile(): void + { + foreach ($this->locales as $locale) { + $store = explode('_', $locale)[1]; + $categories = $this->categoryStorageClient->getCategories($locale, $store); + + foreach ($categories as $category) { + $this->formatCategory($category, '', $locale); + } + } + + $this->writeFile(); + } + + /** + * @param \Generated\Shared\Transfer\CategoryNodeStorageTransfer $category + * @param string $parentCategoryKey + * @param string $locale + * + * @return void + */ + private function formatCategory(CategoryNodeStorageTransfer $category, string $parentCategoryKey, string $locale): void + { + $categoryKey = $this->getCategoryKey($category->getIdCategory()); + $this->categoriesData[$locale][] = [ + self::NODE_KEY => $categoryKey, + self::PARENT_NODE_KEY => $parentCategoryKey, + self::ATTRIBUTES => $this->getCategoryAttributes($category), + ]; + + foreach ($category->getChildren() as $child) { + $this->formatCategory($child, $categoryKey, $locale); + } + } + + /** + * @return void + */ + private function writeFile(): void + { + $file = fopen($this->config->getOutputPath(), 'w'); + fputcsv($file, $this->getHeader()); + $fallbackLocale = $this->config->getFallbackLocale(); + foreach ($this->categoriesData[$fallbackLocale] as $key => $categoryData) { + $data = [ + self::NAVIGATION_KEY => $this->config->getNavigationKey(), + self::NODE_KEY => $categoryData[self::NODE_KEY], + self::PARENT_NODE_KEY => $categoryData[self::PARENT_NODE_KEY], + self::NODE_TYPE => 'category', + ]; + + foreach ($this->getLocales() as $locale) { + $localizedCategoryData = $this->categoriesData[$locale] ?? $this->categoriesData[$fallbackLocale]; + $data += $this->getLocalizedAttributes($localizedCategoryData[$key][self::ATTRIBUTES], $locale); + } + + fputcsv($file, $data); + } + fclose($file); + } + + /** + * @param \Generated\Shared\Transfer\CategoryNodeStorageTransfer $category + * + * @return array + */ + private function getCategoryAttributes(CategoryNodeStorageTransfer $category): array + { + return [ + self::ATTRIBUTE_TITLE => $category->getMetaTitle(), + self::ATTRIBUTE_URL => $category->getUrl(), + self::ATTRIBUTE_CSS => '', + ]; + } + + /** + * @param array $attributes + * @param string $locale + * + * @return array + */ + private function getLocalizedAttributes(array $attributes, string $locale): array + { + $localizedAttributes = []; + foreach ($attributes as $attributeName => $attribute) { + $keyName = $attributeName . '.' . $locale; + $localizedAttributes[$keyName] = $attribute; + } + + return $localizedAttributes; + } + + /** + * @param int $idCategory + * + * @return string + */ + private function getCategoryKey(int $idCategory): string + { + if (isset($this->categoryIdCache[$idCategory])) { + $categoryKey = $this->categoryIdCache[$idCategory]; + } else { + $categoryKey = $this->categoryFacade->findCategoryById($idCategory)->getCategoryKey(); + $this->categoryIdCache[$idCategory] = $categoryKey; + } + + return $categoryKey; + } + + /** + * @return string[] + */ + private function getHeader(): array + { + $header = [ + self::NAVIGATION_KEY, + self::NODE_KEY, + self::PARENT_NODE_KEY, + self::NODE_TYPE, + ]; + + foreach ($this->locales as $locale) { + $localizedHeaderFields = [ + sprintf('%s.%s', self::ATTRIBUTE_TITLE, $locale), + sprintf('%s.%s', self::ATTRIBUTE_URL, $locale), + sprintf('%s.%s', self::ATTRIBUTE_CSS, $locale), + ]; + $header = array_merge($header, $localizedHeaderFields); + } + + return $header; + } + + /** + * @return array + */ + private function getLocales(): array + { + $locales = []; + foreach ($this->storeFacade->getAllStores() as $store) { + $locales = array_merge($locales, $store->getAvailableLocaleIsoCodes()); + } + + return $locales; + } +} diff --git a/src/ValanticSpryker/Zed/NavigationGenerator/Business/NavigationGeneratorBusinessFactory.php b/src/ValanticSpryker/Zed/NavigationGenerator/Business/NavigationGeneratorBusinessFactory.php new file mode 100644 index 0000000..3e67c4d --- /dev/null +++ b/src/ValanticSpryker/Zed/NavigationGenerator/Business/NavigationGeneratorBusinessFactory.php @@ -0,0 +1,55 @@ +getConfig(), + $this->getStoreFacade(), + $this->getCategoryFacade(), + $this->getCategoryStorageClient(), + ); + } + + /** + * @return \Spryker\Zed\Store\Business\StoreFacadeInterface + */ + private function getStoreFacade(): StoreFacadeInterface + { + return $this->getProvidedDependency(NavigationGeneratorDependencyProvider::FACADE_STORE); + } + + /** + * @return \ValanticSpryker\Zed\Category\Business\CategoryFacadeInterface + */ + private function getCategoryFacade(): CategoryFacadeInterface + { + return $this->getProvidedDependency(NavigationGeneratorDependencyProvider::FACADE_CATEGORY); + } + + /** + * @return \ValanticSpryker\Client\CategoryStorage\CategoryStorageClientInterface + */ + private function getCategoryStorageClient(): CategoryStorageClientInterface + { + return $this->getProvidedDependency(NavigationGeneratorDependencyProvider::CLIENT_CATEGORY_STORAGE); + } +} diff --git a/src/ValanticSpryker/Zed/NavigationGenerator/Business/NavigationGeneratorFacade.php b/src/ValanticSpryker/Zed/NavigationGenerator/Business/NavigationGeneratorFacade.php new file mode 100644 index 0000000..b87017d --- /dev/null +++ b/src/ValanticSpryker/Zed/NavigationGenerator/Business/NavigationGeneratorFacade.php @@ -0,0 +1,21 @@ +getFactory()->createNavigationNodeFileGenerator()->generateNavigationNodeFile(); + } +} diff --git a/src/ValanticSpryker/Zed/NavigationGenerator/Business/NavigationGeneratorFacadeInterface.php b/src/ValanticSpryker/Zed/NavigationGenerator/Business/NavigationGeneratorFacadeInterface.php new file mode 100644 index 0000000..681d7fb --- /dev/null +++ b/src/ValanticSpryker/Zed/NavigationGenerator/Business/NavigationGeneratorFacadeInterface.php @@ -0,0 +1,13 @@ +setName(static::COMMAND_NAME) + ->setDescription('Generates navigation-node.csv based on imported category data'); + } + + /** + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Output\OutputInterface $output + * + * @return int + */ + protected function execute(InputInterface $input, OutputInterface $output): int + { + $this->getFacade()->generateNavigationNodeFile(); + + return static::CODE_SUCCESS; + } +} diff --git a/src/ValanticSpryker/Zed/NavigationGenerator/NavigationGeneratorConfig.php b/src/ValanticSpryker/Zed/NavigationGenerator/NavigationGeneratorConfig.php new file mode 100644 index 0000000..f1bf62c --- /dev/null +++ b/src/ValanticSpryker/Zed/NavigationGenerator/NavigationGeneratorConfig.php @@ -0,0 +1,35 @@ +get(NavigationGeneratorConstants::OUTPUT_PATH, APPLICATION_ROOT_DIR . '/data/import/common/common/navigation_node.csv'); + } + + /** + * @return string + */ + public function getFallbackLocale(): string + { + return $this->get(NavigationGeneratorConstants::FALLBACK_LOCALE, 'de_DE'); + } + + /** + * @return string + */ + public function getNavigationKey(): string + { + return $this->get(NavigationGeneratorConstants::NAVIGATION_KEY, 'MAIN_NAVIGATION'); + } +} diff --git a/src/ValanticSpryker/Zed/NavigationGenerator/NavigationGeneratorDependencyProvider.php b/src/ValanticSpryker/Zed/NavigationGenerator/NavigationGeneratorDependencyProvider.php new file mode 100644 index 0000000..3dd23d2 --- /dev/null +++ b/src/ValanticSpryker/Zed/NavigationGenerator/NavigationGeneratorDependencyProvider.php @@ -0,0 +1,75 @@ +addStoreFacade($container); + $this->addCategoryFacade($container); + $this->addCategoryStorageClient($container); + + return $container; + } + + /** + * @param \Spryker\Zed\Kernel\Container $container + * + * @return void + */ + private function addStoreFacade(Container $container): void + { + $container->set( + static::FACADE_STORE, + fn (Container $container): StoreFacadeInterface => $container->getLocator()->store()->facade(), + ); + } + + /** + * @param \Spryker\Zed\Kernel\Container $container + * + * @return void + */ + private function addCategoryFacade(Container $container): void + { + $container->set( + static::FACADE_CATEGORY, + fn (Container $container): CategoryFacadeInterface => $container->getLocator()->category()->facade(), + ); + } + + /** + * @param \Spryker\Zed\Kernel\Container $container + * + * @return void + */ + private function addCategoryStorageClient(Container $container): void + { + $container->set( + static::CLIENT_CATEGORY_STORAGE, + fn (Container $container): CategoryStorageClientInterface => $container->getLocator()->categoryStorage()->client(), + ); + } +} diff --git a/tests/ValanticSprykerTest/.gitkeep b/tests/ValanticSprykerTest/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/_bootstrap.php b/tests/_bootstrap.php new file mode 100644 index 0000000..641a6dd --- /dev/null +++ b/tests/_bootstrap.php @@ -0,0 +1,11 @@ +