diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 90c3f00a..a6182aab 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,212 +1,182 @@ name: Build on: - push: - branches-ignore: - - 'dependabot/**' - pull_request: ~ - release: - types: [created] - schedule: - - - cron: "0 1 * * 6" # Run at 1am every Saturday - workflow_dispatch: ~ + push: + branches-ignore: + - 'dependabot/**' + pull_request: ~ + release: + types: [ created ] + schedule: + - cron: "0 1 * * 6" # Run at 1am every Saturday + workflow_dispatch: ~ jobs: - tests: - runs-on: ubuntu-latest - - name: "Sylius ${{ matrix.sylius }}, PHP ${{ matrix.php }}, Symfony ${{ matrix.symfony }}, MySQL ${{ matrix.mysql }}, Node ${{ matrix.node }}" - - strategy: - fail-fast: false - matrix: - php: [ "8.1", "8.2", "8.3" ] - symfony: [ "^6.0" ] - sylius: [ "~1.13.0" ] - node: [ "18.x", "20.x" ] - mysql: [ "5.7", "8.0" ] + tests: + runs-on: ubuntu-latest + + name: "Sylius ${{ matrix.sylius }}, PHP ${{ matrix.php }}, Symfony ${{ matrix.symfony }}, MySQL ${{ matrix.mysql }}, Node ${{ matrix.node }}" + + strategy: + fail-fast: false + matrix: + php: [ "8.1", "8.2", "8.3" ] + symfony: [ "^5.4", "^6.0" ] + sylius: [ "^1.12", "^1.13" ] + node: [ "18.x", "20.x" ] + mysql: [ "5.7", "8.0" ] + env: + APP_ENV: test + DATABASE_URL: "mysql://root:root@127.0.0.1/sylius?serverVersion=${{ matrix.mysql }}" + + steps: + - uses: actions/checkout@v3 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: "${{ matrix.php }}" + extensions: intl + tools: symfony + coverage: none + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: "${{ matrix.node }}" + + - name: Shutdown default MySQL + run: sudo service mysql stop + + - name: Setup MySQL + uses: mirromutth/mysql-action@v1.1 + with: + mysql version: "${{ matrix.mysql }}" + mysql root password: "root" + + - name: Configure sysctl limits + run: | + sudo swapoff -a + sudo sysctl -w vm.swappiness=1 + sudo sysctl -w fs.file-max=262144 + sudo sysctl -w vm.max_map_count=262144 + + - name: Runs Elasticsearch + uses: elastic/elastic-github-actions/elasticsearch@master + with: + stack-version: 7.16.3 + + - name: Output PHP version for Symfony CLI + run: php -v | head -n 1 | awk '{ print $2 }' > .php-version + + - name: Install certificates + run: symfony server:ca:install + + - name: Run Chrome Headless + run: google-chrome-stable --enable-automation --disable-background-networking --no-default-browser-check --no-first-run --disable-popup-blocking --disable-default-apps --allow-insecure-localhost --disable-translate --disable-extensions --no-sandbox --enable-features=Metal --headless --remote-debugging-port=9222 --window-size=2880,1800 --proxy-server='direct://' --proxy-bypass-list='*' http://127.0.0.1 > /dev/null 2>&1 & + + - name: Run webserver + run: (cd tests/Application && symfony server:start --port=8080 --dir=public --daemon) + + - name: Get Composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache Composer + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ hashFiles('**/composer.json **/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php-${{ matrix.php }}-composer- + + - name: Restrict Symfony version + if: matrix.symfony != '' + run: | + composer global config --no-plugins allow-plugins.symfony/flex true + composer global require --no-progress --no-scripts --no-plugins "symfony/flex:^1.10" + composer config extra.symfony.require "${{ matrix.symfony }}" + + - name: Restrict Sylius version + if: matrix.sylius != '' + run: composer require "sylius/sylius:${{ matrix.sylius }}" --no-update --no-scripts --no-interaction + + - name: Install PHP dependencies + run: composer install --no-interaction --no-scripts + + - name: Install Behat driver + run: vendor/bin/bdi browser:google-chrome drivers + + - name: Get Yarn cache directory + id: yarn-cache + run: echo "::set-output name=dir::$(yarn cache dir)" + + - name: Cache Yarn + uses: actions/cache@v4 + with: + path: ${{ steps.yarn-cache.outputs.dir }} + key: ${{ runner.os }}-node-${{ matrix.node }}-yarn-${{ hashFiles('**/package.json **/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-node-${{ matrix.node }}-yarn- + + - name: Install JS dependencies + run: (cd tests/Application && yarn install) + + - name: Prepare test application database + run: | + (cd tests/Application && bin/console doctrine:database:create -vvv) + (cd tests/Application && bin/console doctrine:schema:create -vvv) + + - name: Prepare test application assets + run: | + (cd tests/Application && bin/console assets:install public -vvv) + (cd tests/Application && yarn encore production) + + - name: Prepare test application cache + run: (cd tests/Application && bin/console cache:warmup -vvv) + + - name: Load fixtures in test application + run: (cd tests/Application && bin/console sylius:fixtures:load -n) + + - name: Validate composer.json + run: composer validate --ansi --strict + + - name: Validate database schema + run: (cd tests/Application && bin/console doctrine:schema:validate) + + - name: Run PHPSpec + run: vendor/bin/phpspec run --ansi -f progress --no-interaction + + - name: Run PHPUnit + run: vendor/bin/phpunit --colors=always + + - name: Run Behat + if: ${{ matrix.sylius != '^1.13.0' }} + run: vendor/bin/behat --colors --strict -vvv --no-interaction --tags '~@sylius113' || vendor/bin/behat --colors --strict -vvv --no-interaction --rerun --tags '~@sylius113' + + - name: Run Behat + if: ${{ matrix.sylius == '^1.13.0' }} + run: vendor/bin/behat --colors --strict -vvv --no-interaction --tags '~@sylius112' || vendor/bin/behat --colors --strict -vvv --no-interaction --rerun --tags '~@sylius112' + + - name: Upload Behat logs + uses: actions/upload-artifact@v3 + if: failure() + with: + name: Behat logs + path: etc/build/ + if-no-files-found: ignore + + - name: Run PHPUnit + run: vendor/bin/phpunit --colors=always + + - name: Failed build Slack notification + uses: rtCamp/action-slack-notify@v2 + if: ${{ failure() && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master') }} env: - APP_ENV: test - DATABASE_URL: "mysql://root:root@127.0.0.1/sylius?serverVersion=${{ matrix.mysql }}" - - steps: - - - uses: actions/checkout@v2 - - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: "${{ matrix.php }}" - extensions: intl - tools: symfony - coverage: none - - - - name: Setup Node - uses: actions/setup-node@v1 - with: - node-version: "${{ matrix.node }}" - - - - name: Shutdown default MySQL - run: sudo service mysql stop - - - - name: Setup MySQL - uses: mirromutth/mysql-action@v1.1 - with: - mysql version: "${{ matrix.mysql }}" - mysql root password: "root" - - - - name: Configure sysctl limits - run: | - sudo swapoff -a - sudo sysctl -w vm.swappiness=1 - sudo sysctl -w fs.file-max=262144 - sudo sysctl -w vm.max_map_count=262144 - - - - name: Runs Elasticsearch - uses: elastic/elastic-github-actions/elasticsearch@master - with: - stack-version: 7.16.3 - - - - name: Output PHP version for Symfony CLI - run: php -v | head -n 1 | awk '{ print $2 }' > .php-version - - - - name: Install certificates - run: symfony server:ca:install - - - - name: Run Chrome Headless - run: google-chrome-stable --enable-automation --disable-background-networking --no-default-browser-check --no-first-run --disable-popup-blocking --disable-default-apps --allow-insecure-localhost --disable-translate --disable-extensions --no-sandbox --enable-features=Metal --headless --remote-debugging-port=9222 --window-size=2880,1800 --proxy-server='direct://' --proxy-bypass-list='*' http://127.0.0.1 > /dev/null 2>&1 & - - - - name: Run webserver - run: (cd tests/Application && symfony server:start --port=8080 --dir=public --daemon) - - - - name: Get Composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - - name: Cache Composer - uses: actions/cache@v2 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ hashFiles('**/composer.json **/composer.lock') }} - restore-keys: | - ${{ runner.os }}-php-${{ matrix.php }}-composer- - - - - name: Restrict Symfony version - if: matrix.symfony != '' - run: | - composer global config --no-plugins allow-plugins.symfony/flex true - composer global require --no-progress --no-scripts --no-plugins "symfony/flex:^1.10" - composer config extra.symfony.require "${{ matrix.symfony }}" - - - - name: Restrict Sylius version - if: matrix.sylius != '' - run: composer require "sylius/sylius:${{ matrix.sylius }}" --no-update --no-scripts --no-interaction - - - - name: Install PHP dependencies - run: composer install --no-interaction --no-scripts - - - - name: Get Yarn cache directory - id: yarn-cache - run: echo "::set-output name=dir::$(yarn cache dir)" - - - - name: Cache Yarn - uses: actions/cache@v2 - with: - path: ${{ steps.yarn-cache.outputs.dir }} - key: ${{ runner.os }}-node-${{ matrix.node }}-yarn-${{ hashFiles('**/package.json **/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-node-${{ matrix.node }}-yarn- - - - - name: Install JS dependencies - run: (cd tests/Application && yarn install) - - - - name: Prepare test application database - run: | - (cd tests/Application && bin/console doctrine:database:create -vvv) - (cd tests/Application && bin/console doctrine:schema:create -vvv) - - - - name: Prepare test application assets - run: | - (cd tests/Application && bin/console assets:install public -vvv) - (cd tests/Application && yarn encore production) - - - - name: Prepare test application cache - run: (cd tests/Application && bin/console cache:warmup -vvv) - - - - name: Load fixtures in test application - run: (cd tests/Application && bin/console sylius:fixtures:load -n) - - - - name: Validate composer.json - run: composer validate --ansi --strict - - - - name: Validate database schema - run: (cd tests/Application && bin/console doctrine:schema:validate) - - - name: Run ECS - run: vendor/bin/ecs check src - - - - name: Run PHPSpec - run: vendor/bin/phpspec run --ansi -f progress --no-interaction - - - - name: Run Behat - if: ${{ matrix.sylius != '~1.13.0' }} - run: vendor/bin/behat --colors --strict -vvv --no-interaction --tags '~@sylius113' || vendor/bin/behat --colors --strict -vvv --no-interaction --rerun --tags '~@sylius113' - - - - name: Run Behat - if: ${{ matrix.sylius == '~1.13.0' }} - run: vendor/bin/behat --colors --strict -vvv --no-interaction --tags '~@sylius112' || vendor/bin/behat --colors --strict -vvv --no-interaction --rerun --tags '~@sylius112' - - - - - name: Upload Behat logs - uses: actions/upload-artifact@v2 - if: failure() - with: - name: Behat logs - path: etc/build/ - if-no-files-found: ignore - - - - name: Run PHPUnit - run: vendor/bin/phpunit --colors=always - - - - name: Failed build Slack notification - uses: rtCamp/action-slack-notify@v2 - if: ${{ failure() && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master') }} - env: - SLACK_CHANNEL: ${{ secrets.FAILED_BUILD_SLACK_CHANNEL }} - SLACK_COLOR: ${{ job.status }} - SLACK_ICON: https://github.com/rtCamp.png?size=48 - SLACK_MESSAGE: ':x:' - SLACK_TITLE: Failed build on ${{ github.event.repository.name }} repository - SLACK_USERNAME: ${{ secrets.FAILED_BUILD_SLACK_USERNAME }} - SLACK_WEBHOOK: ${{ secrets.FAILED_BUILD_SLACK_WEBHOOK }} + SLACK_CHANNEL: ${{ secrets.FAILED_BUILD_SLACK_CHANNEL }} + SLACK_COLOR: ${{ job.status }} + SLACK_ICON: https://github.com/rtCamp.png?size=48 + SLACK_MESSAGE: ':x:' + SLACK_TITLE: Failed build on ${{ github.event.repository.name }} repository + SLACK_USERNAME: ${{ secrets.FAILED_BUILD_SLACK_USERNAME }} + SLACK_WEBHOOK: ${{ secrets.FAILED_BUILD_SLACK_WEBHOOK }} diff --git a/.github/workflows/coding_standard.yml b/.github/workflows/coding_standard.yml new file mode 100644 index 00000000..8f49a540 --- /dev/null +++ b/.github/workflows/coding_standard.yml @@ -0,0 +1,81 @@ +name: Coding standard + +on: + push: + branches-ignore: + - 'dependabot/**' + pull_request: ~ + release: + types: [ created ] + workflow_dispatch: ~ + +jobs: + tests: + runs-on: ubuntu-latest + + name: "Sylius ${{ matrix.sylius }}, PHP ${{ matrix.php }}, Symfony ${{ matrix.symfony }}" + + strategy: + fail-fast: false + matrix: + php: [ "8.1", "8.2", "8.3" ] + symfony: [ "^5.4", "^6.4" ] + sylius: [ "^1.12", "^1.13" ] + node: [ "18.x", "20.x" ] + + steps: + - uses: actions/checkout@v3 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: "${{ matrix.php }}" + extensions: intl + tools: symfony + coverage: none + + - name: Get Composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache Composer + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ hashFiles('**/composer.json', '**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php-${{ matrix.php }}-composer- + + - name: Restrict Symfony version + if: matrix.symfony != '' + run: | + composer global config --no-plugins allow-plugins.symfony/flex true + composer global require --no-progress --no-scripts --no-plugins "symfony/flex:^1.10" + composer config extra.symfony.require "${{ matrix.symfony }}" + + - name: Restrict Sylius version + if: matrix.sylius != '' + run: composer require "sylius/sylius:${{ matrix.sylius }}" --no-update --no-scripts --no-interaction + + - name: Install PHP dependencies + run: composer install --no-interaction + env: + SYMFONY_REQUIRE: ${{ matrix.symfony }} + + - name: Run PHPStan + run: vendor/bin/phpstan analyse -c phpstan.neon -l 8 src/ + + - name: Run ECS + run: vendor/bin/ecs + + - name: Failed build Slack notification + uses: rtCamp/action-slack-notify@v2 + if: ${{ failure() && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master') }} + env: + SLACK_CHANNEL: ${{ secrets.FAILED_BUILD_SLACK_CHANNEL }} + SLACK_COLOR: ${{ job.status }} + SLACK_ICON: https://github.com/rtCamp.png?size=48 + SLACK_MESSAGE: ':x:' + SLACK_TITLE: Failed build on ${{ github.event.repository.name }} repository + SLACK_USERNAME: ${{ secrets.FAILED_BUILD_SLACK_USERNAME }} + SLACK_WEBHOOK: ${{ secrets.FAILED_BUILD_SLACK_WEBHOOK }} diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 00000000..109ffc4a --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,17 @@ +parameters: + level: 8 + reportUnmatchedIgnoredErrors: false + paths: + - src + + excludePaths: + # Sitemap dependent providers + - 'src/SitemapProvider' + - 'src/Importer/AbstractImporter' + - 'tests/Application/config/bootstrap.php' + - 'tests/Fixture/PageFixtureTest.php' + - 'src/Controller/Helper' + ignoreErrors: + - identifier: missingType.iterableValue + - identifier: missingType.generics + - '#.*NodeParentInterface.*#' diff --git a/src/CompilerPass/AuthenticationManagerPolyfillPass.php b/src/CompilerPass/AuthenticationManagerPolyfillPass.php index a310ed98..15b5a9e5 100644 --- a/src/CompilerPass/AuthenticationManagerPolyfillPass.php +++ b/src/CompilerPass/AuthenticationManagerPolyfillPass.php @@ -17,7 +17,7 @@ final class AuthenticationManagerPolyfillPass implements CompilerPassInterface { - public function process(ContainerBuilder $container) + public function process(ContainerBuilder $container): void { if ( false === $container->has('security.authentication_manager') diff --git a/src/Context/TaxonContext.php b/src/Context/TaxonContext.php index 15037b6d..19df2b04 100644 --- a/src/Context/TaxonContext.php +++ b/src/Context/TaxonContext.php @@ -16,6 +16,7 @@ use Sylius\Component\Core\Model\TaxonInterface; use Sylius\Component\Locale\Context\LocaleContextInterface; use Sylius\Component\Taxonomy\Repository\TaxonRepositoryInterface; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; final class TaxonContext implements TaxonContextInterface @@ -29,9 +30,12 @@ public function __construct( public function getTaxon(): TaxonInterface { - $slug = $this->requestStack->getCurrentRequest()->get('slug'); + /** @var Request $request */ + $request = $this->requestStack->getCurrentRequest(); + + $slug = $request->get('slug'); $localeCode = $this->localeContext->getLocaleCode(); - /** @var TaxonInterface $taxon */ + /** @var TaxonInterface|null $taxon */ $taxon = $this->taxonRepository->findOneBySlug($slug, $localeCode); if (null === $slug || null === $taxon) { diff --git a/src/Controller/Action/Api/ListProductsByPartialNameAction.php b/src/Controller/Action/Api/ListProductsByPartialNameAction.php index 283fba10..006f16f6 100644 --- a/src/Controller/Action/Api/ListProductsByPartialNameAction.php +++ b/src/Controller/Action/Api/ListProductsByPartialNameAction.php @@ -39,7 +39,8 @@ public function __invoke(Request $request): Response return new JsonResponse($itemsResponse->toArray()); } - $products = $this->namedProductsFinder->findByNamePart($request->query->get('query')); + /** @var array $products */ + $products = $this->namedProductsFinder->findByNamePart((string) $request->query->get('query')); /** @var ProductInterface $product */ foreach ($products as $product) { @@ -48,10 +49,10 @@ public function __invoke(Request $request): Response } $itemsResponse->addItem(new Item( - $productMainTaxon->getName(), - $product->getName(), + (string) $productMainTaxon->getName(), + (string) $product->getName(), $product->getShortDescription(), - $this->productSlugTransformer->transform($product), + (string) $this->productSlugTransformer->transform($product), $this->productChannelPriceTransformer->transform($product), $this->productImageTransformer->transform($product) )); diff --git a/src/Controller/Action/Shop/AbstractSearchAction.php b/src/Controller/Action/Shop/AbstractSearchAction.php index fbd0ceaa..a32d249f 100644 --- a/src/Controller/Action/Shop/AbstractSearchAction.php +++ b/src/Controller/Action/Shop/AbstractSearchAction.php @@ -14,6 +14,7 @@ use BitBag\SyliusElasticsearchPlugin\Controller\RequestDataHandler\DataHandlerInterface; use BitBag\SyliusElasticsearchPlugin\Finder\ShopProductsFinderInterface; +use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\FormInterface; use Twig\Environment; @@ -30,9 +31,15 @@ public function __construct( protected function clearInvalidEntries(FormInterface $form, array $requestData): array { + /** @var FormError $error */ foreach ($form->getErrors(true) as $error) { + /** @var FormInterface $errorOrigin */ $errorOrigin = $error->getOrigin(); - $path = ($errorOrigin->getParent()->getPropertyPath() ?? '') . $errorOrigin->getPropertyPath(); + + /** @var FormInterface $parent */ + $parent = $errorOrigin->getParent(); + + $path = ($parent->getPropertyPath() ?? '') . $errorOrigin->getPropertyPath(); $keys = explode('][', trim($path, '[]')); diff --git a/src/Controller/Action/Shop/SiteWideProductsSearchAction.php b/src/Controller/Action/Shop/SiteWideProductsSearchAction.php index 6b47f321..a0df90dd 100644 --- a/src/Controller/Action/Shop/SiteWideProductsSearchAction.php +++ b/src/Controller/Action/Shop/SiteWideProductsSearchAction.php @@ -14,6 +14,7 @@ use BitBag\SyliusElasticsearchPlugin\Form\Type\SearchType; use BitBag\SyliusElasticsearchPlugin\Model\Search; +use BitBag\SyliusElasticsearchPlugin\Model\SearchBox; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -29,8 +30,11 @@ public function __invoke(Request $request): Response /** @var Search $search */ $search = $form->getData(); + /** @var SearchBox $searchBox */ + $searchBox = $search->getBox(); + $data = array_merge( - ['query' => $search->getBox()->getQuery()], + ['query' => $searchBox->getQuery()], ['facets' => $search->getFacets()], $this->dataHandler->retrieveData($request->query->all()), ); diff --git a/src/Controller/RequestDataHandler/ShopProductListDataHandler.php b/src/Controller/RequestDataHandler/ShopProductListDataHandler.php index bef607de..ebd3bcd4 100644 --- a/src/Controller/RequestDataHandler/ShopProductListDataHandler.php +++ b/src/Controller/RequestDataHandler/ShopProductListDataHandler.php @@ -32,10 +32,11 @@ public function __construct( public function retrieveData(array $requestData): array { + $data = []; $taxon = $this->taxonContext->getTaxon(); $data[$this->namePropertyPrefix] = (string) $requestData[$this->namePropertyPrefix]; - $data[$this->taxonsProperty] = strtolower($taxon->getCode()); + $data[$this->taxonsProperty] = strtolower((string) $taxon->getCode()); $data['taxon'] = $taxon; $data = array_merge( $data, @@ -77,7 +78,7 @@ private function handleAttributesPrefixedProperty( return; } - $attributeTypes = $this->getAttributeTypes($attributesDefinitions); + $attributeTypes = $this->getAttributeTypes((array) $attributesDefinitions); foreach ($requestData['attributes'] as $key => $value) { if (!is_array($value) || 0 !== strpos($key, $this->attributePropertyPrefix)) { diff --git a/src/Controller/RequestDataHandler/ShopProductsSortDataHandler.php b/src/Controller/RequestDataHandler/ShopProductsSortDataHandler.php index 1fd5c14c..87378153 100644 --- a/src/Controller/RequestDataHandler/ShopProductsSortDataHandler.php +++ b/src/Controller/RequestDataHandler/ShopProductsSortDataHandler.php @@ -37,11 +37,12 @@ public function retrieveData(array $requestData): array $availableSorters = [$this->soldUnitsProperty, $this->createdAtProperty, $this->pricePropertyPrefix]; $availableSorting = [self::SORT_ASC_INDEX, self::SORT_DESC_INDEX]; - if (!in_array($orderBy, $availableSorters) || !in_array($sort, $availableSorting)) { + if (!in_array($orderBy, $availableSorters, true) || !in_array($sort, $availableSorting, true)) { throw new UnexpectedValueException(); } if ($this->pricePropertyPrefix === $orderBy) { + /** @var string $channelCode */ $channelCode = $this->channelContext->getChannel()->getCode(); $orderBy = $this->channelPricingNameResolver->resolvePropertyName($channelCode); } diff --git a/src/Controller/Response/DTO/Item.php b/src/Controller/Response/DTO/Item.php index 1d6db042..1d75711c 100644 --- a/src/Controller/Response/DTO/Item.php +++ b/src/Controller/Response/DTO/Item.php @@ -77,10 +77,10 @@ public function toArray(): array return [ 'taxon_name' => $this->taxonName(), 'name' => $this->name(), - 'description' => $this->description() ?: '', + 'description' => $this->description() ?? '', 'slug' => $this->slug(), 'price' => $this->price(), - 'image' => $this->image() ?: '', + 'image' => $this->image() ?? '', ]; } } diff --git a/src/EventListener/OrderProductsListener.php b/src/EventListener/OrderProductsListener.php index a15e8844..0cde92a5 100644 --- a/src/EventListener/OrderProductsListener.php +++ b/src/EventListener/OrderProductsListener.php @@ -16,6 +16,7 @@ use FOS\ElasticaBundle\Persister\ObjectPersisterInterface; use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Core\Model\OrderItemInterface; +use Sylius\Component\Resource\Model\ResourceInterface; use Symfony\Component\EventDispatcher\GenericEvent; use Webmozart\Assert\Assert; @@ -34,7 +35,10 @@ public function updateOrderProducts(GenericEvent $event): void /** @var OrderItemInterface $orderItem */ foreach ($order->getItems() as $orderItem) { - $this->resourceRefresher->refresh($orderItem->getProduct(), $this->productPersister); + /** @var ResourceInterface $product */ + $product = $orderItem->getProduct(); + + $this->resourceRefresher->refresh($product, $this->productPersister); } } } diff --git a/src/EventListener/ProductTaxonIndexListener.php b/src/EventListener/ProductTaxonIndexListener.php index efd31e1d..a84e0a87 100644 --- a/src/EventListener/ProductTaxonIndexListener.php +++ b/src/EventListener/ProductTaxonIndexListener.php @@ -15,6 +15,7 @@ use BitBag\SyliusElasticsearchPlugin\Refresher\ResourceRefresherInterface; use FOS\ElasticaBundle\Persister\ObjectPersisterInterface; use Sylius\Component\Core\Model\ProductTaxonInterface; +use Sylius\Component\Resource\Model\ResourceInterface; final class ProductTaxonIndexListener { @@ -26,6 +27,9 @@ public function __construct( public function updateIndex(ProductTaxonInterface $productTaxon): void { - $this->resourceRefresher->refresh($productTaxon->getProduct(), $this->objectPersister); + /** @var ResourceInterface $product */ + $product = $productTaxon->getProduct(); + + $this->resourceRefresher->refresh($product, $this->objectPersister); } } diff --git a/src/EventListener/ResourceIndexListener.php b/src/EventListener/ResourceIndexListener.php index 3cf5faca..954e6e22 100644 --- a/src/EventListener/ResourceIndexListener.php +++ b/src/EventListener/ResourceIndexListener.php @@ -34,6 +34,7 @@ public function __construct( public function updateIndex(GenericEvent $event): void { + /** @var ResourceInterface|null $resource */ $resource = $event->getSubject(); Assert::isInstanceOf($resource, ResourceInterface::class); @@ -41,21 +42,25 @@ public function updateIndex(GenericEvent $event): void $method = $config[self::GET_PARENT_METHOD_KEY] ?? null; if (null !== $method && method_exists($resource, $method)) { + /** @phpstan-ignore-next-line Variable method call on mixed or other bugs */ $resource = $resource->$method(); } if ($resource instanceof $config[self::MODEL_KEY]) { + /** @phpstan-ignore-next-line refresh method needs ResourceInterface but ECS doesn't see $resource variable in method. */ $this->resourceRefresher->refresh($resource, $config[self::SERVICE_ID_KEY]); } if ($resource instanceof ProductInterface || $resource instanceof ProductVariantInterface) { if (ProductAttribute::class === $config[self::MODEL_KEY]) { foreach ($this->attributeRepository->findAll() as $attribute) { + /** @var ResourceInterface $attribute */ $this->resourceRefresher->refresh($attribute, $config[self::SERVICE_ID_KEY]); } } if (ProductOption::class === $config[self::MODEL_KEY]) { foreach ($this->optionRepository->findAll() as $option) { + /** @var ResourceInterface $option */ $this->resourceRefresher->refresh($option, $config[self::SERVICE_ID_KEY]); } } diff --git a/src/Facet/AttributeFacet.php b/src/Facet/AttributeFacet.php index f6fe4845..1e83f43e 100644 --- a/src/Facet/AttributeFacet.php +++ b/src/Facet/AttributeFacet.php @@ -52,14 +52,14 @@ public function getBucketLabel(array $bucket): string public function getLabel(): string { - return $this->getProductAttribute()->getName(); + return (string) $this->getProductAttribute()->getName(); } private function getFieldName(): string { return sprintf( '%s_%s.keyword', - $this->attributeNameResolver->resolvePropertyName($this->getProductAttribute()->getCode()), + $this->attributeNameResolver->resolvePropertyName((string) $this->getProductAttribute()->getCode()), $this->localeContext->getLocaleCode() ); } diff --git a/src/Facet/OptionFacet.php b/src/Facet/OptionFacet.php index a1431d9c..6ff99ca2 100644 --- a/src/Facet/OptionFacet.php +++ b/src/Facet/OptionFacet.php @@ -49,11 +49,11 @@ public function getBucketLabel(array $bucket): string public function getLabel(): string { - return $this->productOption->getName(); + return (string) $this->productOption->getName(); } private function getFieldName(): string { - return $this->optionNameResolver->resolvePropertyName($this->productOption->getCode()) . '.keyword'; + return $this->optionNameResolver->resolvePropertyName((string) $this->productOption->getCode()) . '.keyword'; } } diff --git a/src/Facet/PriceFacet.php b/src/Facet/PriceFacet.php index 0fddbc25..faea18be 100644 --- a/src/Facet/PriceFacet.php +++ b/src/Facet/PriceFacet.php @@ -36,7 +36,7 @@ public function __construct( public function getAggregation(): AbstractAggregation { $priceFieldName = $this->channelPricingNameResolver->resolvePropertyName( - $this->shopperContext->getChannel()->getCode() + (string) $this->shopperContext->getChannel()->getCode() ); $histogram = new Histogram(self::FACET_ID, $priceFieldName, $this->interval); $histogram->setMinimumDocumentCount(1); @@ -47,7 +47,7 @@ public function getAggregation(): AbstractAggregation public function getQuery(array $selectedBuckets): AbstractQuery { $priceFieldName = $this->channelPricingNameResolver->resolvePropertyName( - $this->shopperContext->getChannel()->getCode() + (string) $this->shopperContext->getChannel()->getCode() ); $query = new BoolQuery(); foreach ($selectedBuckets as $selectedBucket) { diff --git a/src/Finder/NamedProductsFinder.php b/src/Finder/NamedProductsFinder.php index 94871c7e..dc7ba371 100644 --- a/src/Finder/NamedProductsFinder.php +++ b/src/Finder/NamedProductsFinder.php @@ -13,6 +13,7 @@ namespace BitBag\SyliusElasticsearchPlugin\Finder; use BitBag\SyliusElasticsearchPlugin\QueryBuilder\QueryBuilderInterface; +use Elastica\Query\AbstractQuery; use FOS\ElasticaBundle\Finder\FinderInterface; final class NamedProductsFinder implements NamedProductsFinderInterface @@ -26,6 +27,7 @@ public function __construct( public function findByNamePart(string $namePart): ?array { $data = ['query' => $namePart]; + /** @var AbstractQuery $query */ $query = $this->queryBuilder->buildQuery($data); return $this->productsFinder->find($query); diff --git a/src/Finder/ProductAttributesFinder.php b/src/Finder/ProductAttributesFinder.php index 2c2b4c28..ad2326c9 100644 --- a/src/Finder/ProductAttributesFinder.php +++ b/src/Finder/ProductAttributesFinder.php @@ -13,6 +13,7 @@ namespace BitBag\SyliusElasticsearchPlugin\Finder; use BitBag\SyliusElasticsearchPlugin\QueryBuilder\QueryBuilderInterface; +use Elastica\Query\AbstractQuery; use FOS\ElasticaBundle\Finder\FinderInterface; use Sylius\Component\Core\Model\TaxonInterface; @@ -28,8 +29,9 @@ public function __construct( public function findByTaxon(TaxonInterface $taxon): ?array { $data = []; - $data[$this->taxonsProperty] = strtolower($taxon->getCode()); + $data[$this->taxonsProperty] = strtolower((string) $taxon->getCode()); + /** @var AbstractQuery $query */ $query = $this->attributesByTaxonQueryBuilder->buildQuery($data); return $this->attributesFinder->find($query, 20); diff --git a/src/Finder/ProductOptionsFinder.php b/src/Finder/ProductOptionsFinder.php index bcf122ed..8deee9f1 100644 --- a/src/Finder/ProductOptionsFinder.php +++ b/src/Finder/ProductOptionsFinder.php @@ -13,6 +13,7 @@ namespace BitBag\SyliusElasticsearchPlugin\Finder; use BitBag\SyliusElasticsearchPlugin\QueryBuilder\QueryBuilderInterface; +use Elastica\Query\AbstractQuery; use FOS\ElasticaBundle\Finder\FinderInterface; use Sylius\Component\Core\Model\TaxonInterface; @@ -28,8 +29,9 @@ public function __construct( public function findByTaxon(TaxonInterface $taxon): ?array { $data = []; - $data[$this->taxonsProperty] = strtolower($taxon->getCode()); + $data[$this->taxonsProperty] = strtolower((string) $taxon->getCode()); + /** @var AbstractQuery $query */ $query = $this->productOptionsByTaxonQueryBuilder->buildQuery($data); return $this->optionsFinder->find($query, 20); diff --git a/src/Finder/ShopProductsFinder.php b/src/Finder/ShopProductsFinder.php index bc3cafb4..3a869a03 100644 --- a/src/Finder/ShopProductsFinder.php +++ b/src/Finder/ShopProductsFinder.php @@ -31,6 +31,7 @@ public function __construct( public function find(array $data): Pagerfanta { + /** @var Query\BoolQuery $boolQuery */ $boolQuery = $this->queryBuilder->buildQuery($data); if (array_key_exists('facets', $data) && is_array($data['facets'])) { diff --git a/src/Form/Type/AbstractFilterType.php b/src/Form/Type/AbstractFilterType.php index 39f91a2c..cc2de73b 100644 --- a/src/Form/Type/AbstractFilterType.php +++ b/src/Form/Type/AbstractFilterType.php @@ -26,7 +26,7 @@ public function configureOptions(OptionsResolver $resolver): void ]); } - public function getBlockPrefix(): ?string + public function getBlockPrefix(): string { return ''; } diff --git a/src/Form/Type/ChoiceMapper/ProductAttributesMapper.php b/src/Form/Type/ChoiceMapper/ProductAttributesMapper.php index ec57788b..8b2f27dd 100644 --- a/src/Form/Type/ChoiceMapper/ProductAttributesMapper.php +++ b/src/Form/Type/ChoiceMapper/ProductAttributesMapper.php @@ -17,6 +17,7 @@ use BitBag\SyliusElasticsearchPlugin\Formatter\StringFormatterInterface; use BitBag\SyliusElasticsearchPlugin\Repository\ProductAttributeValueRepositoryInterface; use Sylius\Component\Attribute\AttributeType\SelectAttributeType; +use Sylius\Component\Core\Model\Taxon; use Sylius\Component\Locale\Context\LocaleContextInterface; use Sylius\Component\Product\Model\ProductAttributeInterface; @@ -47,6 +48,7 @@ public function mapToChoices(ProductAttributeInterface $productAttribute): array return $choices; } + /** @var Taxon $taxon */ $taxon = $this->taxonContext->getTaxon(); $attributeValues = $this->productAttributeValueRepository->getUniqueAttributeValues($productAttribute, $taxon); diff --git a/src/Form/Type/ChoiceMapper/ProductOptionsMapper.php b/src/Form/Type/ChoiceMapper/ProductOptionsMapper.php index 2284c3f8..d2913686 100644 --- a/src/Form/Type/ChoiceMapper/ProductOptionsMapper.php +++ b/src/Form/Type/ChoiceMapper/ProductOptionsMapper.php @@ -31,6 +31,7 @@ public function mapToChoices(ProductOptionInterface $productOption): array array_walk( $productOptionValues, function (ProductOptionValueInterface $productOptionValue) use (&$choices): void { + /** @var string $value */ $value = $productOptionValue->getValue(); $choices[$value] = $this->stringFormatter->formatToLowercaseWithoutSpaces($value); } diff --git a/src/Form/Type/PriceFilterType.php b/src/Form/Type/PriceFilterType.php index b3ab1131..40c20f1c 100644 --- a/src/Form/Type/PriceFilterType.php +++ b/src/Form/Type/PriceFilterType.php @@ -70,7 +70,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void ], ]) ->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) { - if (!empty($event->getData())) { + if (null !== $event->getData()) { $data = []; foreach ($event->getData() as $key => $item) { $data[$key] = trim($item); diff --git a/src/Form/Type/ProductAttributesFilterType.php b/src/Form/Type/ProductAttributesFilterType.php index 410a1c06..387cf604 100644 --- a/src/Form/Type/ProductAttributesFilterType.php +++ b/src/Form/Type/ProductAttributesFilterType.php @@ -31,8 +31,10 @@ public function __construct( public function buildForm(FormBuilderInterface $builder, array $attributes): void { - foreach ($this->productAttributesContext->getAttributes() as $productAttribute) { - if (in_array($productAttribute->getCode(), $this->excludedAttributes)) { + /** @var array $options */ + $options = $this->productAttributesContext->getAttributes(); + foreach ($options as $productAttribute) { + if (in_array($productAttribute->getCode(), $this->excludedAttributes, true)) { continue; } diff --git a/src/Form/Type/ProductOptionsFilterType.php b/src/Form/Type/ProductOptionsFilterType.php index ec93c8fc..075b9c7e 100644 --- a/src/Form/Type/ProductOptionsFilterType.php +++ b/src/Form/Type/ProductOptionsFilterType.php @@ -30,7 +30,9 @@ public function __construct( public function buildForm(FormBuilderInterface $builder, array $options): void { - foreach ($this->productOptionsContext->getOptions() as $productOption) { + /** @var array $options */ + $options = $this->productOptionsContext->getOptions(); + foreach ($options as $productOption) { $name = $this->optionNameResolver->resolvePropertyName($productOption->getCode()); $choices = $this->productOptionsMapper->mapToChoices($productOption); $choices = array_unique($choices); diff --git a/src/Form/Type/SearchFacetsType.php b/src/Form/Type/SearchFacetsType.php index 1011dbfc..273bb08f 100644 --- a/src/Form/Type/SearchFacetsType.php +++ b/src/Form/Type/SearchFacetsType.php @@ -33,7 +33,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void foreach ($facetData['buckets'] as $bucket) { $choices[$facet->getBucketLabel($bucket)] = $bucket['key']; } - if (!empty($choices)) { + if ([] !== $choices) { $builder ->add( $facetId, diff --git a/src/Model/SearchFacets.php b/src/Model/SearchFacets.php index f275cf95..f7e55f14 100644 --- a/src/Model/SearchFacets.php +++ b/src/Model/SearchFacets.php @@ -18,7 +18,7 @@ final class SearchFacets implements Iterator { private array $selectedBuckets = []; - public function __get(string $facetId) + public function __get(string $facetId): array { if (!array_key_exists($facetId, $this->selectedBuckets)) { return []; @@ -27,7 +27,7 @@ public function __get(string $facetId) return $this->selectedBuckets[$facetId]; } - public function __set(string $facetId, $selectedBuckets) + public function __set(string $facetId, string $selectedBuckets): void { $this->selectedBuckets[$facetId] = $selectedBuckets; } @@ -68,7 +68,7 @@ public function valid(): bool { $key = key($this->selectedBuckets); - return null !== $key && false !== $key; + return null !== $key; } /** diff --git a/src/PropertyBuilder/AttributeBuilder.php b/src/PropertyBuilder/AttributeBuilder.php index 540113ba..8b60284e 100644 --- a/src/PropertyBuilder/AttributeBuilder.php +++ b/src/PropertyBuilder/AttributeBuilder.php @@ -49,22 +49,25 @@ function (ProductInterface $product, Document $document): void { private function resolveProductAttributes(ProductInterface $product, Document $document): void { + /** @var ProductAttributeValue $productAttribute */ foreach ($product->getAttributes() as $productAttribute) { $attribute = $productAttribute->getAttribute(); - if (!$attribute) { + if (null === $attribute) { continue; } - $this->processAttribute($attribute, $productAttribute, $document); } } private function resolveProductAttribute( array $attributeConfiguration, - $attributeValue, + mixed $attributeValue, ProductAttributeValue $productAttribute ): array { - if (SelectAttributeType::TYPE === $productAttribute->getAttribute()->getType()) { + /** @var AttributeInterface $attribute */ + $attribute = $productAttribute->getAttribute(); + + if (SelectAttributeType::TYPE === $attribute->getType()) { $choices = $attributeConfiguration['choices']; if (is_array($attributeValue)) { foreach ($attributeValue as $i => $item) { @@ -87,8 +90,8 @@ private function resolveProductAttribute( break; case $attributeValue instanceof \DateTime: - $attributeFormat = $productAttribute->getAttribute()->getConfiguration()['format'] ?? null; - $defaultFormat = DateAttributeType::TYPE === $productAttribute->getAttribute()->getStorageType() ? + $attributeFormat = $attribute->getConfiguration()['format'] ?? null; + $defaultFormat = DateAttributeType::TYPE === $attribute->getStorageType() ? self::DEFAULT_DATE_FORMAT : self::DEFAULT_DATE_TIME_FORMAT ; @@ -109,6 +112,7 @@ private function processAttribute( ProductAttributeValue $productAttribute, Document $document ): void { + /** @var string $attributeCode */ $attributeCode = $attribute->getCode(); $attributeConfiguration = $attribute->getConfiguration(); @@ -122,7 +126,7 @@ private function processAttribute( $productAttribute ); - $values = in_array($attribute->getStorageType(), [DateAttributeType::TYPE, DatetimeAttributeType::TYPE]) ? + $values = in_array($attribute->getStorageType(), [DateAttributeType::TYPE, DatetimeAttributeType::TYPE], true) ? ($values[0] ?? $values) : $values ; diff --git a/src/PropertyBuilder/AttributeTaxonsBuilder.php b/src/PropertyBuilder/AttributeTaxonsBuilder.php index 9f087a7c..009168dc 100644 --- a/src/PropertyBuilder/AttributeTaxonsBuilder.php +++ b/src/PropertyBuilder/AttributeTaxonsBuilder.php @@ -34,7 +34,7 @@ public function consumeEvent(PostTransformEvent $event): void if (!$documentAttribute instanceof AttributeInterface || !$documentAttribute instanceof ProductAttributeInterface - || in_array($documentAttribute->getCode(), $this->excludedAttributes) + || in_array($documentAttribute->getCode(), $this->excludedAttributes, true) ) { return; } diff --git a/src/PropertyBuilder/ChannelPricingBuilder.php b/src/PropertyBuilder/ChannelPricingBuilder.php index 0c98d253..ab557845 100644 --- a/src/PropertyBuilder/ChannelPricingBuilder.php +++ b/src/PropertyBuilder/ChannelPricingBuilder.php @@ -39,8 +39,11 @@ function (ProductInterface $product, Document $document): void { $productVariant = $product->getVariants()->first(); foreach ($productVariant->getChannelPricings() as $channelPricing) { + /** @var string $channelCode */ + $channelCode = $channelPricing->getChannelCode(); + $propertyName = $this->channelPricingNameResolver - ->resolvePropertyName($channelPricing->getChannelCode()); + ->resolvePropertyName($channelCode); $document->set($propertyName, $channelPricing->getPrice()); } diff --git a/src/PropertyBuilder/OptionBuilder.php b/src/PropertyBuilder/OptionBuilder.php index acc6f6ce..6c19b757 100644 --- a/src/PropertyBuilder/OptionBuilder.php +++ b/src/PropertyBuilder/OptionBuilder.php @@ -17,6 +17,7 @@ use Elastica\Document; use FOS\ElasticaBundle\Event\PostTransformEvent; use Sylius\Component\Core\Model\ProductInterface; +use Sylius\Component\Product\Model\ProductOptionInterface; final class OptionBuilder extends AbstractBuilder { @@ -41,10 +42,18 @@ private function resolveProductOptions(ProductInterface $product, Document $docu { foreach ($product->getVariants() as $productVariant) { foreach ($productVariant->getOptionValues() as $productOptionValue) { - $optionCode = $productOptionValue->getOption()->getCode(); + /** @var ProductOptionInterface $option */ + $option = $productOptionValue->getOption(); + + /** @var string $optionCode */ + $optionCode = $option->getCode(); + + /** @var string $value */ + $value = $productOptionValue->getValue(); + $index = $this->optionNameResolver->resolvePropertyName($optionCode); $options = $document->has($index) ? $document->get($index) : []; - $value = $this->stringFormatter->formatToLowercaseWithoutSpaces($productOptionValue->getValue()); + $value = $this->stringFormatter->formatToLowercaseWithoutSpaces($value); $options[] = $value; $document->set($index, array_values(array_unique($options))); diff --git a/src/PropertyBuilder/ProductCreatedAtPropertyBuilder.php b/src/PropertyBuilder/ProductCreatedAtPropertyBuilder.php index cf844413..c2083b14 100644 --- a/src/PropertyBuilder/ProductCreatedAtPropertyBuilder.php +++ b/src/PropertyBuilder/ProductCreatedAtPropertyBuilder.php @@ -15,6 +15,7 @@ use Elastica\Document; use FOS\ElasticaBundle\Event\PostTransformEvent; use Sylius\Component\Core\Model\ProductInterface; +use Webmozart\Assert\Assert; final class ProductCreatedAtPropertyBuilder extends AbstractBuilder { @@ -29,6 +30,7 @@ public function consumeEvent(PostTransformEvent $event): void $event, ProductInterface::class, function (ProductInterface $product, Document $document): void { + Assert::notNull($product->getCreatedAt()); $createdAt = (int) $product->getCreatedAt()->format('U'); $document->set($this->createdAtProperty, $createdAt); diff --git a/src/PropertyBuilder/ProductDescriptionBuilder.php b/src/PropertyBuilder/ProductDescriptionBuilder.php index 37d92e09..060e16e6 100644 --- a/src/PropertyBuilder/ProductDescriptionBuilder.php +++ b/src/PropertyBuilder/ProductDescriptionBuilder.php @@ -33,8 +33,11 @@ public function consumeEvent(PostTransformEvent $event): void function (ProductInterface $product, Document $document): void { /** @var ProductTranslationInterface $productTranslation */ foreach ($product->getTranslations() as $productTranslation) { + /** @var string $locale */ + $locale = $productTranslation->getLocale(); + $propertyName = $this->productDescriptionNameResolver->resolvePropertyName( - $productTranslation->getLocale() + $locale ); $document->set($propertyName, $productTranslation->getDescription()); } diff --git a/src/PropertyBuilder/ProductNameBuilder.php b/src/PropertyBuilder/ProductNameBuilder.php index 97328762..71a306fc 100644 --- a/src/PropertyBuilder/ProductNameBuilder.php +++ b/src/PropertyBuilder/ProductNameBuilder.php @@ -33,8 +33,11 @@ public function consumeEvent(PostTransformEvent $event): void function (ProductInterface $product, Document $document): void { /** @var ProductTranslationInterface $productTranslation */ foreach ($product->getTranslations() as $productTranslation) { + /** @var string $locale */ + $locale = $productTranslation->getLocale(); + $propertyName = $this->productNameNameResolver - ->resolvePropertyName($productTranslation->getLocale()); + ->resolvePropertyName($locale); $document->set($propertyName, $productTranslation->getName()); } diff --git a/src/PropertyBuilder/ProductShortDescriptionBuilder.php b/src/PropertyBuilder/ProductShortDescriptionBuilder.php index 158be691..8e247567 100644 --- a/src/PropertyBuilder/ProductShortDescriptionBuilder.php +++ b/src/PropertyBuilder/ProductShortDescriptionBuilder.php @@ -33,8 +33,11 @@ public function consumeEvent(PostTransformEvent $event): void function (ProductInterface $product, Document $document): void { /** @var ProductTranslationInterface $productTranslation */ foreach ($product->getTranslations() as $productTranslation) { + /** @var string $locale */ + $locale = $productTranslation->getLocale(); + $propertyName = $this->productShortDescriptionNameResolver->resolvePropertyName( - $productTranslation->getLocale() + $locale ); $document->set($propertyName, $productTranslation->getShortDescription()); } diff --git a/src/PropertyBuilder/ProductTaxonPositionPropertyBuilder.php b/src/PropertyBuilder/ProductTaxonPositionPropertyBuilder.php index b88fd649..ca820ced 100644 --- a/src/PropertyBuilder/ProductTaxonPositionPropertyBuilder.php +++ b/src/PropertyBuilder/ProductTaxonPositionPropertyBuilder.php @@ -16,6 +16,7 @@ use Elastica\Document; use FOS\ElasticaBundle\Event\PostTransformEvent; use Sylius\Component\Core\Model\ProductInterface; +use Sylius\Component\Core\Model\TaxonInterface; final class ProductTaxonPositionPropertyBuilder extends AbstractBuilder { @@ -30,10 +31,16 @@ public function consumeEvent(PostTransformEvent $event): void $event, ProductInterface::class, function (ProductInterface $product, Document $document): void { - foreach ($product->getProductTaxons() as $taxon) { + foreach ($product->getProductTaxons() as $productTaxon) { + /** @var TaxonInterface $taxon */ + $taxon = $productTaxon->getTaxon(); + + /** @var string $code */ + $code = $taxon->getCode(); + $document->set( - $this->taxonPositionNameResolver->resolvePropertyName($taxon->getTaxon()->getCode()), - $taxon->getPosition() + $this->taxonPositionNameResolver->resolvePropertyName($code), + $productTaxon->getPosition() ); } } diff --git a/src/PropertyBuilder/SoldUnitsPropertyBuilder.php b/src/PropertyBuilder/SoldUnitsPropertyBuilder.php index b74682d1..aaeceba8 100644 --- a/src/PropertyBuilder/SoldUnitsPropertyBuilder.php +++ b/src/PropertyBuilder/SoldUnitsPropertyBuilder.php @@ -16,6 +16,7 @@ use Elastica\Document; use FOS\ElasticaBundle\Event\PostTransformEvent; use Sylius\Component\Core\Model\ProductInterface; +use Sylius\Component\Core\Model\ProductVariantInterface; final class SoldUnitsPropertyBuilder extends AbstractBuilder { @@ -33,6 +34,7 @@ public function consumeEvent(PostTransformEvent $event): void function (ProductInterface $product, Document $document): void { $soldUnits = 0; + /** @var ProductVariantInterface $productVariant */ foreach ($product->getVariants() as $productVariant) { $soldUnits += $this->orderItemRepository->countByVariant($productVariant); } diff --git a/src/QueryBuilder/AttributesQueryBuilder/AttributesTypeDateQueryBuilder.php b/src/QueryBuilder/AttributesQueryBuilder/AttributesTypeDateQueryBuilder.php index 357869b6..5e2758b1 100644 --- a/src/QueryBuilder/AttributesQueryBuilder/AttributesTypeDateQueryBuilder.php +++ b/src/QueryBuilder/AttributesQueryBuilder/AttributesTypeDateQueryBuilder.php @@ -24,7 +24,7 @@ class AttributesTypeDateQueryBuilder implements AttributesQueryBuilderCollectorI public function supports(string $type): bool { - return in_array($type, self::AVAILABLE_ATTRIBUTES_TYPE); + return in_array($type, self::AVAILABLE_ATTRIBUTES_TYPE, true); } public function buildQuery(array $data, string $localCode): BoolQuery diff --git a/src/QueryBuilder/AttributesQueryBuilder/AttributesTypeNumberQueryBuilder.php b/src/QueryBuilder/AttributesQueryBuilder/AttributesTypeNumberQueryBuilder.php index 3af17e03..1c4d5937 100644 --- a/src/QueryBuilder/AttributesQueryBuilder/AttributesTypeNumberQueryBuilder.php +++ b/src/QueryBuilder/AttributesQueryBuilder/AttributesTypeNumberQueryBuilder.php @@ -25,7 +25,7 @@ class AttributesTypeNumberQueryBuilder implements AttributesQueryBuilderCollecto public function supports(string $type): bool { - return in_array($type, self::AVAILABLE_ATTRIBUTES_TYPE); + return in_array($type, self::AVAILABLE_ATTRIBUTES_TYPE, true); } public function buildQuery(array $data, string $localCode): BoolQuery diff --git a/src/QueryBuilder/AttributesQueryBuilder/AttributesTypeTextQueryBuilder.php b/src/QueryBuilder/AttributesQueryBuilder/AttributesTypeTextQueryBuilder.php index cc3cc9e8..02e8bc61 100644 --- a/src/QueryBuilder/AttributesQueryBuilder/AttributesTypeTextQueryBuilder.php +++ b/src/QueryBuilder/AttributesQueryBuilder/AttributesTypeTextQueryBuilder.php @@ -25,7 +25,7 @@ class AttributesTypeTextQueryBuilder implements AttributesQueryBuilderCollectorI public function supports(string $type): bool { - return in_array($type, self::AVAILABLE_ATTRIBUTES_TYPE); + return in_array($type, self::AVAILABLE_ATTRIBUTES_TYPE, true); } public function buildQuery(array $data, string $localCode): BoolQuery diff --git a/src/QueryBuilder/FormQueryBuilder/SiteWideFacetsQueryBuilder.php b/src/QueryBuilder/FormQueryBuilder/SiteWideFacetsQueryBuilder.php index eb563524..856d0f24 100644 --- a/src/QueryBuilder/FormQueryBuilder/SiteWideFacetsQueryBuilder.php +++ b/src/QueryBuilder/FormQueryBuilder/SiteWideFacetsQueryBuilder.php @@ -12,7 +12,6 @@ namespace BitBag\SyliusElasticsearchPlugin\QueryBuilder\FormQueryBuilder; use BitBag\SyliusElasticsearchPlugin\Facet\RegistryInterface; -use BitBag\SyliusElasticsearchPlugin\Model\Search; use BitBag\SyliusElasticsearchPlugin\QueryBuilder\QueryBuilderInterface; use Elastica\Query; use Symfony\Component\Form\FormEvent; @@ -27,9 +26,10 @@ public function __construct( public function getQuery(FormEvent $event): Query { - /** @var Search $data */ + /** @var array $data */ $data = $event->getData(); + /** @var Query\BoolQuery $boolQuery */ $boolQuery = $this->queryBuilder->buildQuery([ 'query' => $data['box']['query'] ?? '', ]); diff --git a/src/QueryBuilder/FormQueryBuilder/TaxonFacetsQueryBuilder.php b/src/QueryBuilder/FormQueryBuilder/TaxonFacetsQueryBuilder.php index fc4e1a03..3378c9de 100644 --- a/src/QueryBuilder/FormQueryBuilder/TaxonFacetsQueryBuilder.php +++ b/src/QueryBuilder/FormQueryBuilder/TaxonFacetsQueryBuilder.php @@ -34,6 +34,7 @@ public function getQuery(FormEvent $event, string $namePropertyPrefix): Query $data = $this->shopProductListDataHandler->retrieveData($eventData); + /** @var Query\BoolQuery $boolQuery */ $boolQuery = $this->searchProductsQueryBuilder->buildQuery($data); foreach ($data['facets'] ?? [] as $facetId => $selectedBuckets) { diff --git a/src/QueryBuilder/HasChannelQueryBuilder.php b/src/QueryBuilder/HasChannelQueryBuilder.php index 99d39eb3..e09cdc40 100644 --- a/src/QueryBuilder/HasChannelQueryBuilder.php +++ b/src/QueryBuilder/HasChannelQueryBuilder.php @@ -27,7 +27,9 @@ public function __construct( public function buildQuery(array $data): ?AbstractQuery { $channelQuery = new Terms($this->channelsProperty); - $channelQuery->setTerms([strtolower($this->channelContext->getChannel()->getCode())]); + /** @var string $channelCode */ + $channelCode = $this->channelContext->getChannel()->getCode(); + $channelQuery->setTerms([strtolower($channelCode)]); return $channelQuery; } diff --git a/src/QueryBuilder/HasPriceBetweenQueryBuilder.php b/src/QueryBuilder/HasPriceBetweenQueryBuilder.php index 4efdb367..130e0759 100644 --- a/src/QueryBuilder/HasPriceBetweenQueryBuilder.php +++ b/src/QueryBuilder/HasPriceBetweenQueryBuilder.php @@ -22,6 +22,7 @@ use Sylius\Component\Core\Model\ChannelInterface; use Sylius\Component\Currency\Context\CurrencyContextInterface; use Sylius\Component\Currency\Converter\CurrencyConverterInterface; +use Webmozart\Assert\Assert; final class HasPriceBetweenQueryBuilder implements QueryBuilderInterface { @@ -39,9 +40,15 @@ public function buildQuery(array $data): ?AbstractQuery $dataMinPrice = $this->getDataByKey($data, $this->priceNameResolver->resolveMinPriceName()); $dataMaxPrice = $this->getDataByKey($data, $this->priceNameResolver->resolveMaxPriceName()); + // PHPStan is not right here: Only booleans are allowed in a ternary operator condition, string|null given + // When we change the functionality, it breaks search filtering on empty price fields value + /** @phpstan-ignore-next-line */ $minPrice = $dataMinPrice ? $this->resolveBasePrice($dataMinPrice) : null; + + /** @phpstan-ignore-next-line */ $maxPrice = $dataMaxPrice ? $this->resolveBasePrice($dataMaxPrice) : null; + /** @var string $channelCode */ $channelCode = $this->channelContext->getChannel()->getCode(); $propertyName = $this->channelPricingNameResolver->resolvePropertyName($channelCode); $rangeQuery = new Range(); @@ -62,8 +69,13 @@ private function resolveBasePrice(string $price): int $price = $this->convertFromString($price); /** @var ChannelInterface $channel */ $channel = $this->channelContext->getChannel(); + $channelBaseCurrency = $channel->getBaseCurrency(); + + Assert::notNull($channelBaseCurrency); + $currentCurrencyCode = $this->currencyContext->getCurrencyCode(); - $channelBaseCurrencyCode = $channel->getBaseCurrency()->getCode(); + /** @var string $channelBaseCurrencyCode */ + $channelBaseCurrencyCode = $channelBaseCurrency->getCode(); if ($currentCurrencyCode !== $channelBaseCurrencyCode) { $price = $this->currencyConverter->convert($price, $currentCurrencyCode, $channelBaseCurrencyCode); @@ -80,7 +92,10 @@ private function convertFromString(string $price): int $transformer = new SyliusMoneyTransformer(2, false, NumberFormatter::ROUND_HALFUP, 100); - return $transformer->reverseTransform($price); + /** @var int $convertedPrice */ + $convertedPrice = $transformer->reverseTransform($price); + + return $convertedPrice; } private function getDataByKey(array $data, ?string $key = null): ?string @@ -90,6 +105,7 @@ private function getDataByKey(array $data, ?string $key = null): ?string private function getQueryParamValue(?int $min, ?int $max): ?array { + $paramValue = null; foreach (['gte' => $min, 'lte' => $max] as $key => $value) { if (null !== $value) { $paramValue[$key] = $value; diff --git a/src/QueryBuilder/ProductAttributesByTaxonQueryBuilder.php b/src/QueryBuilder/ProductAttributesByTaxonQueryBuilder.php index afde00fc..0c5c3ce9 100644 --- a/src/QueryBuilder/ProductAttributesByTaxonQueryBuilder.php +++ b/src/QueryBuilder/ProductAttributesByTaxonQueryBuilder.php @@ -14,6 +14,7 @@ use Elastica\Query\AbstractQuery; use Elastica\Query\BoolQuery; +use Webmozart\Assert\Assert; final class ProductAttributesByTaxonQueryBuilder implements QueryBuilderInterface { @@ -27,6 +28,8 @@ public function buildQuery(array $data): ?AbstractQuery $boolQuery = new BoolQuery(); $taxonQuery = $this->hasTaxonQueryBuilder->buildQuery($data); + Assert::notNull($taxonQuery); + $boolQuery->addMust($taxonQuery); return $boolQuery; diff --git a/src/QueryBuilder/ProductOptionsByTaxonQueryBuilder.php b/src/QueryBuilder/ProductOptionsByTaxonQueryBuilder.php index 42c87cec..e6ec4099 100644 --- a/src/QueryBuilder/ProductOptionsByTaxonQueryBuilder.php +++ b/src/QueryBuilder/ProductOptionsByTaxonQueryBuilder.php @@ -14,6 +14,7 @@ use Elastica\Query\AbstractQuery; use Elastica\Query\BoolQuery; +use Webmozart\Assert\Assert; final class ProductOptionsByTaxonQueryBuilder implements QueryBuilderInterface { @@ -27,6 +28,8 @@ public function buildQuery(array $data): ?AbstractQuery $boolQuery = new BoolQuery(); $taxonQuery = $this->hasTaxonQueryBuilder->buildQuery($data); + Assert::notNull($taxonQuery); + $boolQuery->addMust($taxonQuery); return $boolQuery; diff --git a/src/QueryBuilder/SiteWideProductsQueryBuilder.php b/src/QueryBuilder/SiteWideProductsQueryBuilder.php index 0b83d2c5..6b14e572 100644 --- a/src/QueryBuilder/SiteWideProductsQueryBuilder.php +++ b/src/QueryBuilder/SiteWideProductsQueryBuilder.php @@ -14,6 +14,7 @@ use Elastica\Query\AbstractQuery; use Elastica\Query\BoolQuery; +use Webmozart\Assert\Assert; final class SiteWideProductsQueryBuilder implements QueryBuilderInterface { @@ -28,8 +29,14 @@ public function buildQuery(array $data): ?AbstractQuery { $boolQuery = new BoolQuery(); - $boolQuery->addMust($this->isEnabledQueryBuilder->buildQuery([])); - $boolQuery->addMust($this->hasChannelQueryBuilder->buildQuery([])); + $isEnabledQuery = $this->isEnabledQueryBuilder->buildQuery([]); + $hasChannelQuery = $this->hasChannelQueryBuilder->buildQuery([]); + + Assert::notNull($isEnabledQuery); + Assert::notNull($hasChannelQuery); + + $boolQuery->addMust($isEnabledQuery); + $boolQuery->addMust($hasChannelQuery); $nameQuery = $this->containsNameQueryBuilder->buildQuery($data); $this->addMustIfNotNull($nameQuery, $boolQuery); diff --git a/src/QueryBuilder/TaxonProductsQueryBuilder.php b/src/QueryBuilder/TaxonProductsQueryBuilder.php index d81132d9..cc562af5 100644 --- a/src/QueryBuilder/TaxonProductsQueryBuilder.php +++ b/src/QueryBuilder/TaxonProductsQueryBuilder.php @@ -14,6 +14,7 @@ use Elastica\Query\AbstractQuery; use Elastica\Query\BoolQuery; +use Webmozart\Assert\Assert; final class TaxonProductsQueryBuilder implements QueryBuilderInterface { @@ -34,8 +35,14 @@ public function buildQuery(array $data): AbstractQuery { $boolQuery = new BoolQuery(); - $boolQuery->addMust($this->isEnabledQueryBuilder->buildQuery($data)); - $boolQuery->addMust($this->hasChannelQueryBuilder->buildQuery($data)); + $isEnabledQuery = $this->isEnabledQueryBuilder->buildQuery($data); + $hasChannelQuery = $this->hasChannelQueryBuilder->buildQuery($data); + + Assert::notNull($isEnabledQuery); + Assert::notNull($hasChannelQuery); + + $boolQuery->addMust($isEnabledQuery); + $boolQuery->addMust($hasChannelQuery); $nameQuery = $this->containsNameQueryBuilder->buildQuery($data); $this->addMustIfNotNull($nameQuery, $boolQuery); @@ -57,7 +64,9 @@ private function resolveOptionQuery(BoolQuery $boolQuery, array $data): void foreach ($data as $key => $value) { if (0 === strpos($key, $this->optionPropertyPrefix) && 0 < count($value)) { $optionQuery = $this->hasOptionsQueryBuilder->buildQuery(['option' => $key, 'option_values' => $value]); - $boolQuery->addMust($optionQuery); + if (null !== $optionQuery) { + $boolQuery->addMust($optionQuery); + } } } } @@ -67,7 +76,9 @@ private function resolveAttributeQuery(BoolQuery $boolQuery, array $data): void foreach ($data as $key => $value) { if (0 === strpos($key, $this->attributePropertyPrefix) && 0 < count($value)) { $optionQuery = $this->hasAttributesQueryBuilder->buildQuery(['attribute' => $key, 'attribute_values' => $value]); - $boolQuery->addMust($optionQuery); + if (null !== $optionQuery) { + $boolQuery->addMust($optionQuery); + } } } } diff --git a/src/Repository/OrderItemRepository.php b/src/Repository/OrderItemRepository.php index 5ff4dfe1..40c22e43 100644 --- a/src/Repository/OrderItemRepository.php +++ b/src/Repository/OrderItemRepository.php @@ -25,11 +25,14 @@ public function __construct( public function countByVariant(ProductVariantInterface $variant, array $orderStates = []): int { - if (empty($orderStates)) { + if ([] !== $orderStates) { $orderStates = [OrderInterface::STATE_CANCELLED, OrderInterface::STATE_CART]; } - return (int) ($this->baseOrderItemRepository + /** @var EntityRepository $baseOrderItemRepository */ + $baseOrderItemRepository = $this->baseOrderItemRepository; + + return (int) ($baseOrderItemRepository ->createQueryBuilder('oi') ->select('SUM(oi.quantity)') ->join('oi.order', 'o') diff --git a/src/Repository/ProductAttributeRepository.php b/src/Repository/ProductAttributeRepository.php index 2255c193..10f4f56c 100644 --- a/src/Repository/ProductAttributeRepository.php +++ b/src/Repository/ProductAttributeRepository.php @@ -12,7 +12,7 @@ namespace BitBag\SyliusElasticsearchPlugin\Repository; -use Doctrine\ORM\QueryBuilder; +use Doctrine\ORM\EntityRepository; use Sylius\Component\Resource\Repository\RepositoryInterface; class ProductAttributeRepository implements ProductAttributeRepositoryInterface @@ -24,10 +24,11 @@ public function __construct( public function getAttributeTypeByName(string $attributeName): string { - /** @var QueryBuilder $queryBuilder */ - $queryBuilder = $this->productAttributeRepository->createQueryBuilder('p'); + /** @var EntityRepository $queryBuilder */ + $queryBuilder = $this->productAttributeRepository; $result = $queryBuilder + ->createQueryBuilder('p') ->select('p.type') ->where('p.code = :code') ->setParameter(':code', $attributeName) @@ -39,12 +40,15 @@ public function getAttributeTypeByName(string $attributeName): string public function findAllWithTranslations(?string $locale): array { - /** @var QueryBuilder $queryBuilder */ - $queryBuilder = $this->productAttributeRepository->createQueryBuilder('o'); + /** @var EntityRepository $productAttributeRepository */ + $productAttributeRepository = $this->productAttributeRepository; + + $queryBuilder = $productAttributeRepository->createQueryBuilder('o'); if (null !== $locale) { $queryBuilder ->addSelect('translation') + /** @phpstan-ignore-next-line phpstan can't read relationship correctly */ ->leftJoin('o.translations', 'translation', 'ot') ->andWhere('translation.locale = :locale') ->setParameter('locale', $locale) diff --git a/src/Repository/ProductAttributeValueRepository.php b/src/Repository/ProductAttributeValueRepository.php index 4e0730ad..e109ec5a 100644 --- a/src/Repository/ProductAttributeValueRepository.php +++ b/src/Repository/ProductAttributeValueRepository.php @@ -12,6 +12,7 @@ namespace BitBag\SyliusElasticsearchPlugin\Repository; +use Doctrine\ORM\EntityRepository; use Sylius\Component\Attribute\Model\AttributeInterface; use Sylius\Component\Product\Repository\ProductAttributeValueRepositoryInterface as BaseAttributeValueRepositoryInterface; use Sylius\Component\Taxonomy\Model\Taxon; @@ -26,7 +27,10 @@ public function __construct( public function getUniqueAttributeValues(AttributeInterface $productAttribute, Taxon $taxon): array { - $queryBuilder = $this->baseAttributeValueRepository->createQueryBuilder('o'); + /** @var EntityRepository $baseAttributeValueRepository */ + $baseAttributeValueRepository = $this->baseAttributeValueRepository; + + $queryBuilder = $baseAttributeValueRepository->createQueryBuilder('o'); /** @var string|null $storageType */ $storageType = $productAttribute->getStorageType(); diff --git a/src/Repository/ProductOptionRepository.php b/src/Repository/ProductOptionRepository.php index df513c81..07af6300 100644 --- a/src/Repository/ProductOptionRepository.php +++ b/src/Repository/ProductOptionRepository.php @@ -12,7 +12,7 @@ namespace BitBag\SyliusElasticsearchPlugin\Repository; -use Doctrine\ORM\QueryBuilder; +use Doctrine\ORM\EntityRepository; use Sylius\Component\Resource\Repository\RepositoryInterface; class ProductOptionRepository implements ProductOptionRepositoryInterface @@ -24,12 +24,14 @@ public function __construct( public function findAllWithTranslations(?string $locale): array { - /** @var QueryBuilder $queryBuilder */ - $queryBuilder = $this->productOptionRepository->createQueryBuilder('o'); + /** @var EntityRepository $queryBuilder */ + $queryBuilder = $this->productOptionRepository; if (null !== $locale) { $queryBuilder + ->createQueryBuilder('o') ->addSelect('translation') + /** @phpstan-ignore-next-line phpstan can't read relationship correctly */ ->leftJoin('o.translations', 'translation', 'ot') ->andWhere('translation.locale = :locale') ->setParameter('locale', $locale) @@ -37,6 +39,7 @@ public function findAllWithTranslations(?string $locale): array } return $queryBuilder + ->createQueryBuilder('o') ->getQuery() ->getResult() ; diff --git a/src/Repository/ProductVariantRepository.php b/src/Repository/ProductVariantRepository.php index c050f9bf..bb305806 100644 --- a/src/Repository/ProductVariantRepository.php +++ b/src/Repository/ProductVariantRepository.php @@ -26,7 +26,11 @@ public function __construct( public function findOneByOptionValue(ProductOptionValueInterface $productOptionValue): ?ProductVariantInterface { - return $this->baseProductVariantRepository->createQueryBuilder('o') + /** @var EntityRepository $baseProductVariantRepository */ + $baseProductVariantRepository = $this->baseProductVariantRepository; + + return $baseProductVariantRepository + ->createQueryBuilder('o') ->where(':optionValue MEMBER OF o.optionValues') ->setParameter('optionValue', $productOptionValue) ->getQuery() @@ -37,7 +41,11 @@ public function findOneByOptionValue(ProductOptionValueInterface $productOptionV public function findByOptionValue(ProductOptionValueInterface $productOptionValue): array { - return $this->baseProductVariantRepository->createQueryBuilder('o') + /** @var EntityRepository $baseProductVariantRepository */ + $baseProductVariantRepository = $this->baseProductVariantRepository; + + return $baseProductVariantRepository + ->createQueryBuilder('o') ->where(':optionValue MEMBER OF o.optionValues') ->setParameter('optionValue', $productOptionValue) ->getQuery() diff --git a/src/Repository/TaxonRepository.php b/src/Repository/TaxonRepository.php index 07de826b..b0208e0c 100644 --- a/src/Repository/TaxonRepository.php +++ b/src/Repository/TaxonRepository.php @@ -30,15 +30,21 @@ public function __construct( public function getTaxonsByAttributeViaProduct(AttributeInterface $attribute): array { - return $this->baseTaxonRepository + /** @var EntityRepository $taxonRepository */ + $taxonRepository = $this->baseTaxonRepository; + + /** @var EntityRepository $productRepository */ + $productRepository = $this->productRepository; + + return $taxonRepository ->createQueryBuilder('t') ->distinct(true) ->select('t') ->leftJoin($this->productTaxonEntityClass, 'pt', Join::WITH, 'pt.taxon = t.id') ->where( 'pt.product IN(' . - $this - ->productRepository->createQueryBuilder('p') + $productRepository + ->createQueryBuilder('p') ->leftJoin($this->productAttributeEntityClass, 'pav', Join::WITH, 'pav.subject = p.id') ->where('pav.attribute = :attribute') ->getQuery() diff --git a/src/Transformer/Product/ChannelPricingTransformer.php b/src/Transformer/Product/ChannelPricingTransformer.php index 084da818..682cc2c2 100644 --- a/src/Transformer/Product/ChannelPricingTransformer.php +++ b/src/Transformer/Product/ChannelPricingTransformer.php @@ -20,6 +20,7 @@ use Sylius\Component\Core\Model\ProductVariantInterface; use Sylius\Component\Locale\Context\LocaleContextInterface; use Sylius\Component\Product\Resolver\ProductVariantResolverInterface; +use Webmozart\Assert\Assert; final class ChannelPricingTransformer implements TransformerInterface { @@ -33,7 +34,7 @@ public function __construct( public function transform(ProductInterface $product): ?string { - /** @var ChannelInterface|null $channel */ + /** @var ChannelInterface $channel */ $channel = $this->channelContext->getChannel(); if (null === $channelBaseCurrency = $channel->getBaseCurrency()) { @@ -53,6 +54,9 @@ public function transform(ProductInterface $product): ?string return null; } + Assert::integer($productVariantPricing->getPrice()); + Assert::string($channelBaseCurrency->getCode()); + return $this->moneyFormatter->format( $productVariantPricing->getPrice(), $channelBaseCurrency->getCode(), diff --git a/src/Transformer/Product/ImageTransformer.php b/src/Transformer/Product/ImageTransformer.php index 2cfdfbe7..2f793dcd 100644 --- a/src/Transformer/Product/ImageTransformer.php +++ b/src/Transformer/Product/ImageTransformer.php @@ -39,8 +39,11 @@ public function transform(ProductInterface $product): ?string /** @var ImageInterface $productImage */ $productImage = $productThumbnails->first(); - if ($this->canImageBeFiltered($productImage->getPath())) { - return $this->imagineFilter->getUrlOfFilteredImage($productImage->getPath(), self::SYLIUS_THUMBNAIL_FILTER); + /** @var string $path */ + $path = $productImage->getPath(); + + if ($this->canImageBeFiltered($path)) { + return $this->imagineFilter->getUrlOfFilteredImage($path, self::SYLIUS_THUMBNAIL_FILTER); } return $this->imagesPath . $productImage->getPath(); diff --git a/tests/Application/config/bundles.php b/tests/Application/config/bundles.php index a39c4ab4..4055d382 100644 --- a/tests/Application/config/bundles.php +++ b/tests/Application/config/bundles.php @@ -66,9 +66,8 @@ BabDev\PagerfantaBundle\BabDevPagerfantaBundle::class => ['all' => true], ]; - -if ( defined(SyliusCoreBundle::class.'::VERSION_ID') && SyliusCoreBundle::VERSION_ID >= '11300') { +if (defined(SyliusCoreBundle::class . '::VERSION_ID') && SyliusCoreBundle::VERSION_ID >= '11300') { $bundles[Sylius\Abstraction\StateMachine\SyliusStateMachineAbstractionBundle::class] = ['all' => true]; } -return $bundles; \ No newline at end of file +return $bundles;