From c3034d4ff10da385039a5a04ae988e9291820289 Mon Sep 17 00:00:00 2001 From: Jordan Kniest Date: Mon, 17 Jun 2024 16:39:41 +0200 Subject: [PATCH] Add full vitepress documentation page (#69) * Write UPGRADE guide * Rewrote upgrade guide * Add simple vitepress project * Configure colors * Finish first draft of "Getting started" * Add first draft of installation chapter * Add first draft of supported versions * Add first draft of upgrade guide * Add first draft of first fixture page, add uuid command * Add first draft of the "Dependencies & Prioritization" page * Add first draft of grouping chapter * Add first draft of "Available commands" page * Add first draft of "Fixture Helper" page * Add first draft of "PHPUnit & Tests" chapter * Add first draft of "Utility methods" page * Add first draft of "media helper" page * Add first draft of category helpers page * Add first draft of sales channel helper page * Add first draft of salutation page * Add first draft of cms page * Add first drafts for payment- and shipping method pages * Add first draft of "Language & Locale" helpers * Add first drafts of currency and tax page * Finish first draft of all helper pages * Finish examples * Rewrote a lot of pages * finalized all links * Add first try at deployment * Fix wrong variable * Fix base path * Only run on main branch --- .github/workflows/deploy-docs.yml | 43 +++++ .github/workflows/linting.yml | 4 +- .gitignore | 3 + CHANGELOG.md | 1 + Makefile | 2 +- UPGRADE.md | 105 ++++++++++++ _examples/CustomerFixture.php | 31 ++-- bun.lockb | Bin 0 -> 48084 bytes docs/.vitepress/config.mts | 95 +++++++++++ docs/.vitepress/theme/custom.css | 5 + docs/.vitepress/theme/index.js | 4 + docs/examples/customer.md | 66 ++++++++ docs/examples/index.data.js | 3 + docs/examples/index.md | 18 +++ docs/examples/product.md | 71 +++++++++ docs/getting-started.md | 115 ++++++++++++++ docs/helpers/category.md | 17 ++ docs/helpers/cms.md | 17 ++ docs/helpers/currency.md | 17 ++ docs/helpers/database.md | 21 +++ docs/helpers/language-locale.md | 59 +++++++ docs/helpers/media.md | 41 +++++ docs/helpers/payment-method.md | 17 ++ docs/helpers/sales-channel.md | 61 +++++++ docs/helpers/salutation.md | 17 ++ docs/helpers/shipping-method.md | 17 ++ docs/helpers/tax.md | 31 ++++ docs/helpers/utility.md | 19 +++ docs/index.md | 25 +++ docs/installation.md | 99 ++++++++++++ docs/supported-versions.md | 15 ++ docs/upgrade.md | 145 +++++++++++++++++ docs/writing/available-commands.md | 47 ++++++ docs/writing/dependencies-prioritization.md | 68 ++++++++ docs/writing/first-fixture.md | 167 ++++++++++++++++++++ docs/writing/fixture-helper.md | 62 ++++++++ docs/writing/groups.md | 56 +++++++ docs/writing/phpunit-tests.md | 116 ++++++++++++++ package-lock.json | 31 ---- package.json | 16 +- src/Command/UuidCommand.php | 25 +++ src/Utils/LanguageAndLocaleUtils.php | 7 +- 42 files changed, 1719 insertions(+), 60 deletions(-) create mode 100644 .github/workflows/deploy-docs.yml create mode 100755 bun.lockb create mode 100644 docs/.vitepress/config.mts create mode 100644 docs/.vitepress/theme/custom.css create mode 100644 docs/.vitepress/theme/index.js create mode 100644 docs/examples/customer.md create mode 100644 docs/examples/index.data.js create mode 100644 docs/examples/index.md create mode 100644 docs/examples/product.md create mode 100644 docs/getting-started.md create mode 100644 docs/helpers/category.md create mode 100644 docs/helpers/cms.md create mode 100644 docs/helpers/currency.md create mode 100644 docs/helpers/database.md create mode 100644 docs/helpers/language-locale.md create mode 100644 docs/helpers/media.md create mode 100644 docs/helpers/payment-method.md create mode 100644 docs/helpers/sales-channel.md create mode 100644 docs/helpers/salutation.md create mode 100644 docs/helpers/shipping-method.md create mode 100644 docs/helpers/tax.md create mode 100644 docs/helpers/utility.md create mode 100644 docs/index.md create mode 100644 docs/installation.md create mode 100644 docs/supported-versions.md create mode 100644 docs/upgrade.md create mode 100644 docs/writing/available-commands.md create mode 100644 docs/writing/dependencies-prioritization.md create mode 100644 docs/writing/first-fixture.md create mode 100644 docs/writing/fixture-helper.md create mode 100644 docs/writing/groups.md create mode 100644 docs/writing/phpunit-tests.md delete mode 100644 package-lock.json create mode 100644 src/Command/UuidCommand.php diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml new file mode 100644 index 0000000..907f789 --- /dev/null +++ b/.github/workflows/deploy-docs.yml @@ -0,0 +1,43 @@ +name: Deploy documentation + +on: + push: + branches: [main] + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - uses: oven-sh/setup-bun@v1 + - name: Setup pages + uses: actions/configure-pages@v4 + - name: Install dependencies + run: bun install + - name: Build vitepress + run: bun run docs:build + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: docs/.vitepress/dist + + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + needs: build + runs-on: ubuntu-latest + steps: + - name: Deploy to Github Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index e95bc36..d9fd222 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -107,8 +107,10 @@ jobs: - name: Check out code uses: actions/checkout@v4 + - uses: oven-sh/setup-bun@v1 + - name: Install dependencies - run: npm ci + run: bun install - name: Run Prettier run: './node_modules/.bin/prettier --check "src/**/*.{js,scss,yaml,yml,json,md,ts}"' diff --git a/.gitignore b/.gitignore index 294e60b..984d383 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ /src/Resources/app/storefront/node_modules/ composer.lock src/Examples +/docs/.vitepress/dist +/docs/.vitepress/cache +package-lock.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c62e97..3525604 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `deleteEntities` takes an entity name and criteria and deletes all entities which match the criteria - Added a small cache for all utilities. It prevents loading data twice within the same request / command execution - Added small helper function: `$fixtureHelper->ensureNotEmpty` which throws an exception if something is empty (using the PHP empty function) +- Added command `fixture:uuid` which just prints a random UUID ### Changed - Changed argument type on `SalesChannelUtils::getTax()` from `int` to `float` diff --git a/Makefile b/Makefile index 69e1bf7..3d21414 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ shell: ## Install all dependencies dependencies: make docker COMMAND="composer install --no-interaction --optimize-autoloader" - make docker COMMAND="npm ci" + make docker COMMAND="npm install" ## Install all dependencies and prepare everything install: diff --git a/UPGRADE.md b/UPGRADE.md index 465d94d..757cbc4 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,110 @@ # Upgrade +## v2.x -> v3.x +### See changelog +First, review the changes documented in CHANGELOG.md. + +### Support for older versions (Impact: High) +Release V3 has dropped support for PHP 8.1 and Shopware 6.3 & 6.4. The supported versions are now PHP 8.2, PHP 8.3, and Shopware 6.5 and 6.6. + +### Dropped FixtureBag (Impact: High) +Support for the FixtureBag parameter in every `load` method has been removed. Each fixture needs to be updated accordingly: + +#### Before +```php +class CustomerFixture extends Fixture +{ + public function load(FixtureBag $bag): void + { + // ... + } +} +``` + +#### After +```php +class CustomerFixture extends Fixture +{ + public function load(): void + { + // ... + } +} +``` + +### Vendor Fixtures (Impact: Low) +In version 2, fixtures within the `vendor` folder were executed alongside project-specific fixtures. This behavior has changed in V3. Now, only direct fixtures (those not within the `vendor` folder) will be executed. + +Every fixture command now supports an additional flag `--vendor` to include vendor fixtures: +```shell +bin/console fixture:load --vendor +bin/console fixture:load:single --vendor MyFixture +bin/console fixture:load:group --vendor MyGroup +``` + +### Fixture Loader (Impact: Low) +All fixture are loaded from a `FixtureLoader` service. If you never directly accessed the loader and only used the built-in trait and commands, you can ignore this section. + +We have completely rewritten the logic to define which fixtures are executed. The fixture loader now accepts a single argument: `$options`. Within this options object, you can specify exactly how the fixture plugin loads fixtures: + +```php +readonly class FixtureOption +{ + public function __construct( + public bool $dryMode = false, + public ?string $groupName = null, + public array $fixtureNames = [], + public bool $withDependencies = false, + public bool $withVendor = false, + ) { + } +} +``` + +All options are combinable, and the internal commands and traits also use this options object. + +### FixtureTrait +The `FixtureTrait` used for testing has been rewritten to use the new `FixtureOption` structure. + +The `runFixtures` method, which previously took an array of fixture names, now takes a `FixtureOption` class. To achieve the original behavior, you can either provide a `FixtureOption` class with the `$fixtureNames` parameter filled out or use our new alias method: `runSpecificFixtures`, which works like the previous `runFixtures`. The new method also includes a parameter to load all dependencies of those fixtures. + +```php +// Either: +$this->runFixtures(new FixtureOption(fixtureNames: ['MyFixture', 'AnotherFixture'])); + +// Or: +$this->runSpecificFixtures(['MyFixture', 'AnotherFixture']); +``` + +The `runSingleFixtureWithDependencies` method has been replaced with `runSingleFixture`. The first argument is the name of the fixture, and the second argument is a boolean to determine if dependencies should be loaded. + +```php +// Before: +$this->runSingleFixtureWithDependencies('MyFixture'); + +// After: +$this->runSingleFixture('MyFixture', true); +``` + +### Helper methods moved / deleted +Many of our helper methods have been updated. Below is a list of affected methods. All not mentioned helpers still work like in V2: + +- `$this->helper->Category()->getFirst()` is removed. No replacement is available +- `$this->helper->Category()->getByName()` is removed. No replacement is available +- `$this->helper->Customer()->getNotSpecifiedSalutation()` has moved to `$this->helper->Salutation()->getNotSpecifiedSalutation()` +- `$this->helper->SalesChannel()->getCurrencyEuro()` has moved to `$this->helper->Currency()->getCurrencyEuro()` +- `$this->helper->SalesChannel()->getLanguage()` has moved to `$this->helper->LanguageAndLocale()->getLanguage()` +- `$this->helper->SalesChannel()->getLocale()` has moved to `$this->helper->LanguageAndLocale()->getLocale()` +- `$this->helper->SalesChannel()->getCountry()` has moved to `$this->helper->LanguageAndLocale()->getCountry()` +- `$this->helper->SalesChannel()->getSnippetSet()` has moved to `$this->helper->LanguageAndLocale()->getSnippetSet()` +- `$this->helper->SalesChannel()->getTax19()` has moved to `$this->helper->Tax()->getTax19()` +- `$this->helper->SalesChannel()->getTax()` has moved to `$this->helper->Tax()->getTax()` + +### Recommendation: Fixture Helper is now given to any fixture +In V3, every fixture has access to the fixture helper by default using $this->helper. +Therefore, while not strictly a breaking change, we advise against manually loading the fixture helper via dependency injection and instead using the provided helper. + + ## v1.x -> v2.x ### See changelog First have a look at the changes in the CHANGELOG.md diff --git a/_examples/CustomerFixture.php b/_examples/CustomerFixture.php index 6574c0d..e615393 100644 --- a/_examples/CustomerFixture.php +++ b/_examples/CustomerFixture.php @@ -5,46 +5,43 @@ namespace Basecom\FixturePlugin; use Shopware\Core\Framework\Context; -use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface; +use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository; class CustomerFixture extends Fixture { private const CUSTOMER_ID = '0d8eefdd6d32456385580e2ff42431b9'; private const ADDRESS_ID = 'e27dc2b4e85f4a0f9a912a09f07701b0'; - private FixtureHelper $helper; - private EntityRepositoryInterface $customerRepository; - - public function __construct(FixtureHelper $helper, EntityRepositoryInterface $customerRepository) - { - $this->helper = $helper; - $this->customerRepository = $customerRepository; + public function __construct( + private readonly EntityRepository $customerRepository + ) { } - public function load(FixtureBag $bag): void + public function load(): void { $salesChannel = $this->helper->SalesChannel()->getStorefrontSalesChannel(); + $this->helper->ensureNotEmpty($salesChannel); $this->customerRepository->upsert([[ 'id' => self::CUSTOMER_ID, 'salesChannelId' => $salesChannel->getId(), 'groupId' => $salesChannel->getCustomerGroupId(), - 'defaultPaymentMethodId' => $this->helper->PaymentMethod()->getInvoicePaymentMethod()->getId(), + 'defaultPaymentMethodId' => $this->helper->PaymentMethod()->getInvoicePaymentMethod()?->getId(), 'defaultBillingAddress' => [ 'id' => self::ADDRESS_ID, - 'salutationId' => $this->helper->Salutation()->getNotSpecifiedSalutation()->getId(), - 'firstName' => 'John', - 'lastName' => 'Doe', + 'salutationId' => $this->helper->Salutation()->getNotSpecifiedSalutation()?->getId(), + 'firstName' => 'Zoey', + 'lastName' => 'Smith', 'zipcode' => '1234', 'street' => 'Sample Street', 'city' => 'Berlin', - 'countryId' => $this->helper->SalesChannel()->getCountry('DE')->getId(), + 'countryId' => $this->helper->LanguageAndLocale()->getCountry('DE')?->getId(), ], 'defaultShippingAddressId' => self::ADDRESS_ID, - 'salutationId' => $this->helper->Salutation()->getNotSpecifiedSalutation()->getId(), + 'salutationId' => $this->helper->Salutation()->getNotSpecifiedSalutation()?->getId(), 'customerNumber' => '1122', - 'firstName' => 'John', - 'lastName' => 'Doe', + 'firstName' => 'Zoey', + 'lastName' => 'Smith', 'email' => 'test@shopware.dev', 'password' => 'notset', ]], Context::createDefaultContext()); diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..029a44026247a8c63d5da90a8283efc45a397fa4 GIT binary patch literal 48084 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 I|NH*`KMvCtMgRZ+ literal 0 HcmV?d00001 diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts new file mode 100644 index 0000000..fc081d6 --- /dev/null +++ b/docs/.vitepress/config.mts @@ -0,0 +1,95 @@ +import { defineConfig } from 'vitepress' + +// https://vitepress.dev/reference/site-config +export default defineConfig({ + title: "Shopware 6 Fixture Plugin", + description: "The fixture plugin is really helpful if you want to create some static demo data", + base: "/FixturesPlugin", + lastUpdated: true, + themeConfig: { + // https://vitepress.dev/reference/default-theme-config + nav: [ + { text: 'Home', link: '/' }, + { text: 'Getting started', link: '/getting-started' }, + ], + + sidebar: [ + { + text: 'Basics', + items: [ + { text: 'Getting started', link: '/getting-started' }, + { text: 'Installation', link: '/installation' }, + { text: 'Supported versions', link: '/supported-versions' }, + { text: 'Upgrade guide', link: '/upgrade' }, + { text: 'Changelog', link: 'https://github.com/basecom/FixturesPlugin/blob/main/CHANGELOG.md' }, + ] + }, + { + text: 'Writing fixtures', + items: [ + { text: 'Your first fixture', link: '/writing/first-fixture' }, + { text: 'Dependencies & Prioritization', link: '/writing/dependencies-prioritization' }, + { text: 'Grouping', link: '/writing/groups' }, + { text: 'Available commands', link: '/writing/available-commands' }, + { text: 'Fixture Helper', link: '/writing/fixture-helper' }, + { text: 'PHPUnit & Tests', link: '/writing/phpunit-tests' }, + ] + }, + { + text: 'Fixture Helpers', + items: [ + { text: 'Utility methods', link: '/helpers/utility' }, + { text: 'Media Helpers', link: '/helpers/media' }, + { text: 'Category Helpers', link: '/helpers/category' }, + { text: 'Sales Channel Helpers', link: '/helpers/sales-channel' }, + { text: 'Salutation Helpers', link: '/helpers/salutation' }, + { text: 'CMS Helpers', link: '/helpers/cms' }, + { text: 'Payment Method Helpers', link: '/helpers/payment-method' }, + { text: 'Shipping Method Helpers', link: '/helpers/shipping-method' }, + { text: 'Language & Locale Helpers', link: '/helpers/language-locale' }, + { text: 'Currency Helpers', link: '/helpers/currency' }, + { text: 'Tax Helpers', link: '/helpers/tax' }, + { text: 'Database Helpers', link: '/helpers/database' }, + ] + }, + { + text: 'Examples', + items: [ + { text: 'Overview', link: '/examples/' }, + { text: 'Create a customer', link: '/examples/customer' }, + { text: 'Create a product', link: '/examples/product' }, + ], + }, + //{ + // text: 'Contributing', + // items: [ + // { text: 'Internals', link: '/contributing/internals' }, + // { text: 'Contribution guide', link: '/contributing/guide' }, + // ] + //} + ], + + socialLinks: [ + { icon: 'github', link: 'https://github.com/basecom/FixturesPlugin' }, + { icon: 'instagram', link: 'https://www.instagram.com/basecom.de/?hl=en' }, + { icon: 'linkedin', link: 'https://www.linkedin.com/company/basecom-gmbh-&-co.-kg/' }, + ], + + footer: { + message: 'Released under the MIT License.', + copyright: 'Copyright © 2021-2024 basecom GmbH & Co. KG' + }, + + editLink: { + pattern: 'https://github.com/basecom/FixturesPlugin/edit/main/docs/:path', + text: 'Edit this page on GitHub' + }, + + search: { + provider: 'local' + } + }, + markdown: { + lineNumbers: true + } +}) diff --git a/docs/.vitepress/theme/custom.css b/docs/.vitepress/theme/custom.css new file mode 100644 index 0000000..fc15253 --- /dev/null +++ b/docs/.vitepress/theme/custom.css @@ -0,0 +1,5 @@ +:root { + --vp-c-brand-1: #0099ff; + --vp-c-brand-2: #006eff; + } + \ No newline at end of file diff --git a/docs/.vitepress/theme/index.js b/docs/.vitepress/theme/index.js new file mode 100644 index 0000000..508d8b4 --- /dev/null +++ b/docs/.vitepress/theme/index.js @@ -0,0 +1,4 @@ +import DefaultTheme from 'vitepress/theme' +import './custom.css' + +export default DefaultTheme \ No newline at end of file diff --git a/docs/examples/customer.md b/docs/examples/customer.md new file mode 100644 index 0000000..cd31395 --- /dev/null +++ b/docs/examples/customer.md @@ -0,0 +1,66 @@ +--- +example: 'Create a customer' +--- + +# Create a customer + +Here is an example fixture on how to create a new shopware customer. This fixture creates the customer, the associated addresses and sets a password (to `password`): + +```php +helper->SalesChannel()->getStorefrontSalesChannel(); + $this->helper->ensureNotEmpty($salesChannel); + + $this->customerRepository->upsert([[ + 'id' => self::CUSTOMER_ID, + 'salesChannelId' => $salesChannel->getId(), + 'groupId' => $salesChannel->getCustomerGroupId(), + 'defaultPaymentMethodId' => $this->helper->PaymentMethod()->getInvoicePaymentMethod()?->getId(), + 'defaultBillingAddress' => [ + 'id' => self::ADDRESS_ID, + 'salutationId' => $this->helper->Salutation()->getNotSpecifiedSalutation()?->getId(), + 'firstName' => 'Zoey', + 'lastName' => 'Smith', + 'zipcode' => '1234', + 'street' => 'Sample Street', + 'city' => 'Berlin', + 'countryId' => $this->helper->LanguageAndLocale()->getCountry('DE')?->getId(), + ], + 'defaultShippingAddressId' => self::ADDRESS_ID, + 'salutationId' => $this->helper->Salutation()->getNotSpecifiedSalutation()?->getId(), + 'customerNumber' => '1122', + 'firstName' => 'Zoey', + 'lastName' => 'Smith', + 'email' => 'test@shopware.dev', + 'password' => 'notset', + ]], Context::createDefaultContext()); + } +} +``` + +## Used in this example: +- [Command to generate the UUIDs](/writing/available-commands#get-random-uuid) +- [`getStorefrontSalesChannel` helper method](/helpers/sales-channel#getstorefrontsaleschannel) +- [`ensureNotEmpty` helper method](/helpers/utility#ensurenotempty) +- [`getInvoicePaymentMethod` helper method](/helpers/payment-method#getinvoicepaymentmethod) +- [`getNotSpecifiedSalutation` helper method](/helpers/salutation#getnotspecifiedsalutation) +- [`getCountry` helper method](/helpers/language-locale#getcountry) \ No newline at end of file diff --git a/docs/examples/index.data.js b/docs/examples/index.data.js new file mode 100644 index 0000000..51abf41 --- /dev/null +++ b/docs/examples/index.data.js @@ -0,0 +1,3 @@ +import { createContentLoader } from 'vitepress' + +export default createContentLoader('examples/*.md', /* options */) diff --git a/docs/examples/index.md b/docs/examples/index.md new file mode 100644 index 0000000..bbce908 --- /dev/null +++ b/docs/examples/index.md @@ -0,0 +1,18 @@ + + +# Examples + +In the following pages, you'll find a few examples of how to build fixtures. If you need a specific example, feel free to [create a discussion on github](https://github.com/basecom/FixturesPlugin/discussions): + + \ No newline at end of file diff --git a/docs/examples/product.md b/docs/examples/product.md new file mode 100644 index 0000000..db006e0 --- /dev/null +++ b/docs/examples/product.md @@ -0,0 +1,71 @@ +--- +example: 'Create a product' +--- + +# Create a product + +Here is an example fixture on how to create a new shopware product. This fixture creates the product and fills out all the required fields: + +```php +helper->SalesChannel()->getStorefrontSalesChannel(); + $this->helper->ensureNotEmpty($salesChannel); + + $rootCategory = $this->helper->Category->getRootCategory(); + $this->helper->ensureNotEmpty($rootCategory); + + $this->productRepository->upsert([[ + 'id' => self::PRODUCT_ID, + 'name' => 'Example Product', + 'active' => true, + 'productNumber' => '1234', + 'taxId' => $this->helper->Tax()->getTax19()?->getId(), + 'price' => [ + $this->helper->SalesChannel()->getCurrencyEuro()?->getId() => [ + 'net' => 84.03, + 'gross' => 100, + 'linked' => true, + 'currencyId' => $this->helper->SalesChannel()->getCurrencyEuro()?->getId(), + ], + ], + 'stock' => 100, + 'categories' => [['id' => $rootCategory->id]], + 'visibilities' => [ + [ + 'id' => self::VISIBILITY_ID, + 'productId' => self::PRODUCT_ID, + 'salesChannelId' => $salesChannel->getId(), + 'visibility' => 30, + ], + ], + ]], Context::createDefaultContext()); + } +} +``` + +## Used in this example: +- [Command to generate the UUIDs](/writing/available-commands#get-random-uuid) +- [`getStorefrontSalesChannel` helper method](/helpers/sales-channel#getstorefrontsaleschannel) +- [`ensureNotEmpty` helper method](/helpers/utility#ensurenotempty) +- [`getRootCategory` helper method](/helpers/category#getrootcategory) +- [`getTax19` helper method](/helpers/tax.html#gettax19) +- [`getCurrencyEuro` helper method](/helpers/currency#getcurrencyeuro) diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 0000000..2bb8502 --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,115 @@ +# Getting started + +The FixturePlugin for Shopware 6 offers convenient commands and structures to create and manage fixtures for your shop project or plugin. + +## What are Fixtures? +Fixtures are a method to generate demo or example data for any given system. We borrowed the concept and terminology from [DoctrineFixturesBundle](https://symfony.com/bundles/DoctrineFixturesBundle/current/index.html). Essentially, fixtures allow you to create a set of predefined data for your shop, such as products, customers, categories, and anything else you need to run your shop locally. + +Fixtures can also be used in staging or review environments. At [basecom](https://basecom.de), we even use them sometimes for production data, such as email template types, which cannot be created from the admin area. + +## Installation +You can easily install the plugin via Composer in any existing Shopware shop: + +```shell:no-line-numbers +# Install the plugin via Composer +composer require basecom/sw6-fixtures-plugin + +# Refresh the plugin list and install/activate the plugin +bin/console plugin:refresh +bin/console plugin:install --activate BasecomFixturePlugin +``` + +Alternatively, you can download the latest release version from GitHub as a ZIP file and install it via the Admin interface in your shop: [All releases](https://github.com/basecom/FixturesPlugin/releases) + +:::tip +For a more detailed tutorial on installation, please see the dedicated [Installation](/installation) chapter. +::: + +## Your first fixture +After installing the plugin, you can start writing your own fixtures. In this getting started guide, we will begin with a simple fixture that creates a new customer. For more inspiration, see the [Examples](/examples/index) page. + +Each fixture must extend the abstract `Fixture` class and implement the `load` method. Below is a complete example of how to create a new customer. + +Create a new file in the Fixtures subdirectory of your shop or plugin and name it `CustomerFixture.php`: + +```php +helper->SalesChannel()->getStorefrontSalesChannel(); + $this->helper->ensureNotEmpty($salesChannel); + + $this->customerRepository->upsert([[ + 'id' => self::CUSTOMER_ID, + 'salesChannelId' => $salesChannel->getId(), + 'groupId' => $salesChannel->getCustomerGroupId(), + 'defaultPaymentMethodId' => $this->helper->PaymentMethod()->getInvoicePaymentMethod()?->getId(), + 'defaultBillingAddress' => [ + 'id' => self::ADDRESS_ID, + 'salutationId' => $this->helper->Salutation()->getNotSpecifiedSalutation()?->getId(), + 'firstName' => 'Zoey', + 'lastName' => 'Smith', + 'zipcode' => '1234', + 'street' => 'Sample Street', + 'city' => 'Berlin', + 'countryId' => $this->helper->LanguageAndLocale()->getCountry('DE')?->getId(), + ], + 'defaultShippingAddressId' => self::ADDRESS_ID, + 'salutationId' => $this->helper->Salutation()->getNotSpecifiedSalutation()?->getId(), + 'customerNumber' => '1122', + 'firstName' => 'Zoey', + 'lastName' => 'Smith', + 'email' => 'test@shopware.dev', + 'password' => 'notset', + ]], Context::createDefaultContext()); + } +} +``` + +:::tip +For a more detailed guide on writing fixtures, see the [Writing first fixture](/writing/first-fixture) chapter. +::: + +Each fixture must be [tagged](https://symfony.com/doc/current/service_container/tags.html) in the [symfony container](https://symfony.com/doc/current/service_container.html) to be recognized by the FixturePlugin. We recommend adding a generic service definition that tags all classes extending the `Fixture` class. + +Add the following to your `services.yaml` file: + +```yaml +services: + _instanceof: + Basecom\FixturePlugin\Fixture: + tags: ['basecom.fixture'] +``` + +Finally, you can run the fixture by executing the following [Symfony Command](https://symfony.com/doc/current/console.html): + +```shell:no-line-numbers +bin/console fixture:load +``` + +## Next Steps +Congratulations! You've written your first fixture :tada: + +Here are some more useful resources to help you continue: +- [A more detailed explanation about how to write fixtures](/writing/first-fixture) +- [All of our helper methods to make your life easier](/writing/fixture-helper) +- [A lot of example fixture to help you get started](/examples/index) + +Happy Coding! \ No newline at end of file diff --git a/docs/helpers/category.md b/docs/helpers/category.md new file mode 100644 index 0000000..50dc6a4 --- /dev/null +++ b/docs/helpers/category.md @@ -0,0 +1,17 @@ +# Category Helpers + +This helper provides utility methods to work with categories. + +## getRootCategory + +The `getRootCategory` method returns the initial root category of the shop or null if none is found. + +```php +helper->Category()->getRootCategory(); // [!code focus] + } +} +``` diff --git a/docs/helpers/cms.md b/docs/helpers/cms.md new file mode 100644 index 0000000..9cad9ab --- /dev/null +++ b/docs/helpers/cms.md @@ -0,0 +1,17 @@ +# CMS Helpers + +This helper provides utility methods to work with CMS pages and layouts. + +## getDefaultCategoryLayout + +The `getDefaultCategoryLayout` method returns the CMS page entity created by Shopware that represents the default category layout, or null if it doesn't exist. + +```php +helper->Cms()->getDefaultCategoryLayout(); // [!code focus] + } +} +``` diff --git a/docs/helpers/currency.md b/docs/helpers/currency.md new file mode 100644 index 0000000..9056a48 --- /dev/null +++ b/docs/helpers/currency.md @@ -0,0 +1,17 @@ +# Currency Helpers + +This helper provides utility methods to work with currencies. + +## getCurrencyEuro + +The `getCurrencyEuro` method returns the EURO currency, or null if it doesn't exist. + +```php +helper->Currency()->getCurrencyEuro(); // [!code focus] + } +} +``` diff --git a/docs/helpers/database.md b/docs/helpers/database.md new file mode 100644 index 0000000..c7222be --- /dev/null +++ b/docs/helpers/database.md @@ -0,0 +1,21 @@ +# Database Helpers + +The database helpers provide a more generic way of handling the database compared to the other helper methods. + +## deleteEntities +The `deleteEntities` method allows a fixture to delete all entities that match a given criteria. It takes the entity name and criteria as parameters and deletes all found entities. + +```php +helper->Database()->deleteEntities( // [!code focus] + entity: ProductDefinition::ENTITY_NAME, // [!code focus] + criteria: (new Criteria())->addFilter(new EqualsFilter('name', 'Example')) // [!code focus] + ); // [!code focus] + } +} +``` + +This example would remove all products that have the name "Example." diff --git a/docs/helpers/language-locale.md b/docs/helpers/language-locale.md new file mode 100644 index 0000000..eec7d63 --- /dev/null +++ b/docs/helpers/language-locale.md @@ -0,0 +1,59 @@ +# Language & Locale Helpers + +This helper provides utility methods to work with languages, locales, snippet sets, and countries. + +## getLanguage + +The `getLanguage` method takes the name of any language as a parameter and returns the language entity that corresponds to that name, or null if none is found. + +```php +helper->LanguageAndLocale()->getLanguage('Deutsch'); // [!code focus] + } +} +``` + +## getLocale + +The `getLocale` method takes the ISO code of any locale as a parameter and returns the locale entity that corresponds to that code, or null if none is found. + +```php +helper->LanguageAndLocale()->getLocale('de-DE'); // [!code focus] + } +} +``` + +## getCountry + +The `getCountry` method takes the ISO code of any country as a parameter and returns the country entity that corresponds to that code, or null if none is found. + +```php +helper->LanguageAndLocale()->getCountry('DE'); // [!code focus] + } +} +``` + +## getSnippetSet + +The `getSnippetSet` method takes the ISO code of any locale as a parameter and returns the snippet set entity that is associated with that locale, or null if none is found. + +```php +helper->LanguageAndLocale()->getSnippetSet('de-DE'); // [!code focus] + } +} +``` \ No newline at end of file diff --git a/docs/helpers/media.md b/docs/helpers/media.md new file mode 100644 index 0000000..794ab33 --- /dev/null +++ b/docs/helpers/media.md @@ -0,0 +1,41 @@ +# Media Helpers + +This helper provides utility methods to work with media assets. + +## getDefaultFolder + +The `getDefaultFolder` method is originally copied from [shopwares core](https://github.com/shopware/shopware/blob/6.5.x/src/Core/Content/Media/MediaService.php#L132) and made public for use in fixtures. + +It searches for the default folder for any given entity (e.g., product) and returns the media folder entity or null if not found. + +```php +helper->Media()->getDefaultFolder('product'); // [!code focus] + } +} +``` + +## upload +This method "uploads" a real file within Shopware. It takes a real file path and uploads it as a complete media entity: + +```php +helper->Media()->getDefaultFolder('product')?->getId(); + $this->helper->ensureNotEmpty($folderId); + + $this->helper->Media()->upload( // [!code focus] + mediaId: '019021d21d9571309bdc48db825032f4', // [!code focus] + folderId: $folderId, // [!code focus] + fileName: '/path/to/the/real/file.png', // [!code focus] + extension: 'png', // [!code focus] + contentType: 'image/png' // [!code focus] + ); // [!code focus] + } +} +``` \ No newline at end of file diff --git a/docs/helpers/payment-method.md b/docs/helpers/payment-method.md new file mode 100644 index 0000000..a31c0e2 --- /dev/null +++ b/docs/helpers/payment-method.md @@ -0,0 +1,17 @@ +# Payment Method Helpers + +This helper provides utility methods to work with payment methods. + +## getInvoicePaymentMethod + +The `getInvoicePaymentMethod` method returns the default invoice payment method of Shopware, or null if it doesn't exist. + +```php +helper->PaymentMethod()->getInvoicePaymentMethod(); // [!code focus] + } +} +``` diff --git a/docs/helpers/sales-channel.md b/docs/helpers/sales-channel.md new file mode 100644 index 0000000..0432a51 --- /dev/null +++ b/docs/helpers/sales-channel.md @@ -0,0 +1,61 @@ +# Sales Channel Helpers + +This helper provides utility methods to work with sales channels. + +## getStorefrontSalesChannel + +The `getStorefrontSalesChannel` method returns the first sales channel of type `Storefront`, or null if it does not exist. + +```php +helper->SalesChannel()->getStorefrontSalesChannel(); // [!code focus] + } +} +``` + +## getHeadlessSalesChannel + +The `getHeadlessSalesChannel` method returns the first sales channel of type `Headless`, or null if it does not exist. + +```php +helper->SalesChannel()->getHeadlessSalesChannel(); // [!code focus] + } +} +``` + +## getProductComparisonSalesChannel + +The `getProductComparisonSalesChannel` method returns the first sales channel of type `Product Comparison` (in the admin it is called Product Feed), or null if it does not exist. + +```php +helper->SalesChannel()->getProductComparisonSalesChannel(); // [!code focus] + } +} +``` + +## getSalesChannelByType + +The `getSalesChannelByType` method takes a type parameter and returns the first sales channel of that specific type, or null if it does not exist. + +```php +helper->SalesChannel()->getSalesChannelByType( // [!code focus] + Defaults::SALES_CHANNEL_TYPE_PRODUCT_COMPARISON // [!code focus] + ); // [!code focus] + } +} +``` diff --git a/docs/helpers/salutation.md b/docs/helpers/salutation.md new file mode 100644 index 0000000..fe1599a --- /dev/null +++ b/docs/helpers/salutation.md @@ -0,0 +1,17 @@ +# Salutation Helpers + +This helper provides utility methods to work with salutations. + +## getNotSpecifiedSalutation + +The `getNotSpecifiedSalutation` method returns the salutation "Not specified", or null if it doesn't exist. + +```php +helper->Salutation()->getNotSpecifiedSalutation(); // [!code focus] + } +} +``` diff --git a/docs/helpers/shipping-method.md b/docs/helpers/shipping-method.md new file mode 100644 index 0000000..a4cfb97 --- /dev/null +++ b/docs/helpers/shipping-method.md @@ -0,0 +1,17 @@ +# Shipping Method Helpers + +This helper provides utility methods to work with shipping methods. + +## getFirstShippingMethod + +The `getFirstShippingMethod` method returns the first active shipping method, or null if none exists. + +```php +helper->ShippingMethod()->getFirstShippingMethod(); // [!code focus] + } +} +``` diff --git a/docs/helpers/tax.md b/docs/helpers/tax.md new file mode 100644 index 0000000..39e6329 --- /dev/null +++ b/docs/helpers/tax.md @@ -0,0 +1,31 @@ +# Tax Helpers + +This helper provides utility methods to work with taxes. + +## getTax19 + +The `getTax19` method returns the tax entity with a tax rate of 19%, or null if it doesn't exist. + +```php +helper->Tax()->getTax19(); // [!code focus] + } +} +``` + +## getTax + +The `getTax` method takes a tax rate as a parameter and returns the tax entity with that given tax rate, or null if it doesn't exist. + +```php +helper->Tax()->getTax(16.0); // [!code focus] + } +} +``` diff --git a/docs/helpers/utility.md b/docs/helpers/utility.md new file mode 100644 index 0000000..f22d397 --- /dev/null +++ b/docs/helpers/utility.md @@ -0,0 +1,19 @@ +# Utility Methods +## ensureNotEmpty +The `ensureNotEmpty` method on the `FixtureHelper` checks that any given variable is not [empty](https://www.php.net/manual/en/function.empty.php). If it is, it will throw a `LogicException`. + +This method also includes the necessary annotations so that [PHPStan](https://phpstan.org/) and [Psalm](https://psalm.dev/) don't throw any errors afterward: + +```php +helper->SalesChannel()->getStorefrontSalesChannel(); + $this->helper->ensureNotEmpty($salesChannel); // [!code focus] + + // Static code analysis now knows that `$salesChannel` exists and is not empty/null. // [!code focus] + $salesChannel->getId(); + } +} +``` \ No newline at end of file diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..c6f82a3 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,25 @@ +--- +# https://vitepress.dev/reference/default-theme-home-page +layout: home + +hero: + name: "Fixture Plugin" + text: "for Shopware 6" + tagline: "Made by basecom" + actions: + - theme: brand + text: Getting started + link: /getting-started + - theme: alt + text: Changelog + link: /changelog + +features: + - title: Structured fixtures + details: Fixtures can be prioritized, have dependencies and can be filtered. + - title: Dozens of helper methods + details: We provide a lot of helper methods to load / create data within shopware. + - title: PHPUnit support + details: A custom trait allows the usage Fixtures within your PHPUnit tests +--- + diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 0000000..831488b --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,99 @@ +# Installation + +There are multiple ways to install the plugin. The recommended method is to use [Composer](https://getcomposer.org/) for the installation. + +## Install via composer + +You can install the plugin via Composer by requiring it. This method follows all of Shopware's best practices for easy installation: + +```shell:no-line-numbers +composer require basecom/sw6-fixtures-plugin +``` + +After installing the plugin via Composer, you'll need to instruct Shopware to load the plugin. To do this, refresh the plugin table and then install and activate the plugin with the following commands (in your Shopware instance): + +```shell:no-line-numbers +bin/console plugin:refresh +bin/console plugin:install --activate BasecomFixturePlugin +``` + +:::warning NEXT STEPS +After the installation, you'll need to modify the service container configuration. See [Tag the fixtures](#tag-the-fixtures) for the next steps. +::: + +## Install via ZIP file + +Alternatively, you can install the package via a ZIP file. GitHub automatically provides downloads for each tagged version. You can find all downloads on the [Github Releases Page](https://github.com/basecom/FixturesPlugin/releases). + +After downloading the ZIP file, either upload it via the Admin area (Admin > Extensions) or place the contents of the ZIP file in the `custom/plugins` directory of your Shopware installation. + +Once the plugin is installed, you'll need to instruct Shopware to load the plugin. To do this, refresh the plugin table and then install and activate the plugin. This can be done either through the admin extensions page or by using the following commands (in your Shopware instance): + +```shell:no-line-numbers +bin/console plugin:refresh +bin/console plugin:install --activate BasecomFixturePlugin +``` + +:::warning NEXT STEPS +After the installation, you'll need to modify the service container configuration. See [Tag the fixtures](#tag-the-fixtures) for the next steps. +::: + +## Tag the fixtures +The FixturePlugin automatically finds all fixtures within your project using [Symfony Container Tags](https://symfony.com/doc/current/service_container/tags.html). This means that each fixture you write must be tagged within the service container. + +### Tag all fixtures automatically +The recommended approach is to configure Symfony to automatically tag all classes that extend the `Fixture` class. To do this, navigate to your `services.yaml` file (either within your specific plugin/bundle or the shop itself) and add the following lines: + +```yaml +services: + _instanceof: + Basecom\FixturePlugin\Fixture: + tags: ['basecom.fixture'] +``` + +This configuration will automatically detect any class that inherits from the `Basecom\FixturePlugin\Fixture` class and add the `basecom.fixture` tag. For more detailed information, refer to the [Symfony Documentation](https://symfony.com/doc/current/service_container/tags.html). + +### Tag each fixture individually +Alternatively, you can tag each fixture class individually. The steps are similar to the automatic tagging method. After you [create your fixture](/writing/first-fixture), you'll need to add the fixture to your `services.yaml` file (either within your specific plugin/bundle or the shop itself) and add the `basecom.fixture` tag to it: + +```yaml +services: + Your\Full\Namespace\Fixtures\CustomerFixture: + tags: ['basecom.fixture'] +``` + +## Use a specific or non-stable version + +### Specific version +If you want to install a specific version, you'll need to provide the version number. Refer to the [CHANGELOG](https://github.com/basecom/FixturesPlugin/blob/main/CHANGELOG.md) for a list of all versions. + +With Composer, you can specify the version either in the `composer.json` file or directly via the install command: + +```shell:no-line-numbers +# This will install version 2: +composer require basecom/sw6-fixtures-plugin:^2.0 + +# This will install version 2.2.1 +composer require basecom/sw6-fixtures-plugin:2.2.1 +``` + +For the ZIP download, simply choose the ZIP file for the desired version. + +### In-development version +If you want to install the in-development version, you can install the `main` branch version. To do this, specify the version `dev-main` in the Composer command: + +```shell:no-line-numbers +composer require basecom/sw6-fixtures-plugin:dev-main +``` + +:::danger +The in-development version may contain undocumented breaking changes or bugs! Please use with caution. +::: + +## Next Steps +Here are some more useful resources to help you continue: +- [A detailed explanation about how to write fixtures](/writing/first-fixture) +- [All of our helper methods to make your life easier](/writing/fixture-helper) +- [A lot of example fixture to help you get started](/examples/index) + +Happy Coding! \ No newline at end of file diff --git a/docs/supported-versions.md b/docs/supported-versions.md new file mode 100644 index 0000000..f248244 --- /dev/null +++ b/docs/supported-versions.md @@ -0,0 +1,15 @@ +# Supported versions + +Please use the following table to check which version of the FixturePlugin can be used with your PHP and Shopware versions: + +| Shopware Version | PHP Versions | Newest FixturePlugin version | Supported | +|------------------|--------------|------------------------------|-----------| +| 6.6.* | v8.2, v8.3 | v3.0.* | ✅ | +| 6.5.* | v8.2, v8.3 | v3.0.* | ✅ | +| 6.5.* | v8.1 | v2.0.* | ❌ | +| 6.4.* | v8.1, v8.2 | v2.0.* | ❌ | +| 6.3.* | v8.1, v8.2 | v2.0.* | ❌ | + +:::info +We strive to support new Shopware and PHP versions as quickly as possible. If there is a new version out and it is not yet supported, feel free to contribute and help us expedite the update process! +::: diff --git a/docs/upgrade.md b/docs/upgrade.md new file mode 100644 index 0000000..5038284 --- /dev/null +++ b/docs/upgrade.md @@ -0,0 +1,145 @@ +--- +next: + text: 'Your first fixture' + link: '/writing/first-fixture' +--- + +# Upgrade Guide + +[[toc]] + +## Upgrading from v2 to v3 +:::info SEE CHANGELOG +For a comprehensive list of all changes, please refer to the [CHANGELOG](https://github.com/basecom/FixturesPlugin/blob/main/CHANGELOG.md). This document will only cover the breaking changes. +::: + +### Dropped support for older versions Impact: High +Release v3 has dropped support for PHP 8.1 and Shopware versions 6.3 and 6.4. The supported versions are now PHP 8.2, PHP 8.3, and Shopware versions 6.5 and 6.6. + +Refer to the [Supported versions](/supported-versions) page for a complete list of supported Shopware and PHP versions. + +### Removed FixtureBag Impact: High +Support for the FixtureBag parameter in the `load` method has been removed. Each fixture needs to be updated accordingly: + +```php:no-line-numbers +class CustomerFixture extends Fixture +{ + public function load(FixtureBag $bag): void // [!code --] + public function load(): void // [!code ++] + { + // ... + } +} +``` + +### Moved & Deleted some helper methods Impact: High +Many of our helper methods have been updated. Below is a list of the affected methods. All helpers not mentioned still work as in v2: + +- `$this->helper->Category()->getFirst()` is removed. No replacement is available +- `$this->helper->Category()->getByName()` is removed. No replacement is available +- `$this->helper->Customer()->getNotSpecifiedSalutation()` has moved to `$this->helper->Salutation()->getNotSpecifiedSalutation()` +- `$this->helper->SalesChannel()->getCurrencyEuro()` has moved to `$this->helper->Currency()->getCurrencyEuro()` +- `$this->helper->SalesChannel()->getLanguage()` has moved to `$this->helper->LanguageAndLocale()->getLanguage()` +- `$this->helper->SalesChannel()->getLocale()` has moved to `$this->helper->LanguageAndLocale()->getLocale()` +- `$this->helper->SalesChannel()->getCountry()` has moved to `$this->helper->LanguageAndLocale()->getCountry()` +- `$this->helper->SalesChannel()->getSnippetSet()` has moved to `$this->helper->LanguageAndLocale()->getSnippetSet()` +- `$this->helper->SalesChannel()->getTax19()` has moved to `$this->helper->Tax()->getTax19()` +- `$this->helper->SalesChannel()->getTax()` has moved to `$this->helper->Tax()->getTax()` + +### Changed methods on the FixtureTrait Impact: Medium +The `FixtureTrait` used for testing has been rewritten to use the new `FixtureOption` structure. + +The `runFixtures` method, which previously took an array of fixture names, now takes a `FixtureOption` class. To achieve the original behavior, you can either provide a `FixtureOption` class with the `$fixtureNames` parameter filled out or use our new alias method `runSpecificFixtures`, which works like the previous `runFixtures`. The new method also includes a parameter to load all dependencies of those fixtures. + +```php:no-line-numbers +// Before: +$this->runFixtures(['MyFixture', 'AnotherFixture']); // [!code --] + +// After: +$this->runSpecificFixtures(['MyFixture', 'AnotherFixture']); // [!code ++] +$this->runFixtures(new FixtureOption(fixtureNames: ['MyFixture', 'AnotherFixture'])); // [!code ++] +``` + +The `runSingleFixtureWithDependencies` method has been replaced with `runSingleFixture`. The first argument is the name of the fixture, and the second argument is a boolean to determine if dependencies should be loaded. + +```php:no-line-numbers +// Before: +$this->runSingleFixtureWithDependencies('MyFixture'); // [!code --] + +// After: +$this->runSingleFixture('MyFixture', true); // [!code ++] +``` + +### Vendor Fixtures don't run by default anymore Impact: Low +In version 2, fixtures within the `vendor` folder were executed alongside project-specific fixtures. This behavior has changed in v3. Now, only direct fixtures (those not within the `vendor` folder) will be executed. + +Every fixture command now supports an additional flag `--vendor` to include vendor fixtures: +```shell:no-line-numbers +bin/console fixture:load --vendor +bin/console fixture:load:single --vendor MyFixture +bin/console fixture:load:group --vendor MyGroup +``` + +### Rewrote the fixture loader Impact: Low +All fixtures are now loaded from a `FixtureLoader` service. If you have never directly accessed the loader and only used the built-in traits and commands, you can ignore this section. + +We have completely rewritten the logic to define which fixtures are executed. The fixture loader now accepts a single argument: `$options`. Within this options object, you can specify exactly how the FixturePlugin loads fixtures. + +```php +readonly class FixtureOption +{ + public function __construct( + public bool $dryMode = false, + public ?string $groupName = null, + public array $fixtureNames = [], + public bool $withDependencies = false, + public bool $withVendor = false, + ) { + } +} +``` + +All options are combinable, and the internal commands and traits also utilize this options object. + + +### Fixture Helper is now given to any fixture Recommendation +In v3, every fixture has access to the fixture helper by default using `$this->helper`. While not strictly a breaking change, we advise against manually loading the fixture helper via dependency injection and instead using the provided helper. + +```php:no-line-numbers +helper->doSomething(); + } +} +``` + + +## Upgrading from v1 to v2 +:::info SEE CHANGELOG +For a comprehensive list of all changes, please refer to the [CHANGELOG](https://github.com/basecom/FixturesPlugin/blob/main/CHANGELOG.md). This document will only cover the breaking changes. +::: + +### Helper methods have been split Impact: High +Instead of calling the helper methods like `$helper->getInvoicePaymentMethod()`, you now need to call the +sub util class: `$helper->PaymentMethod()->getInvoicePaymentMethod()`. + +The following util classes have been added: +```php:no-line-numbers +$fixtureHelper->Media() +$fixtureHelper->Category() +$fixtureHelper->SalesChannel() +$fixtureHelper->Customer() +$fixtureHelper->Cms() +$fixtureHelper->PaymentMethod() +$fixtureHelper->ShippingMethod() +``` + +:::info +We haven't removed any helper methods in this release. We only moved them! +::: diff --git a/docs/writing/available-commands.md b/docs/writing/available-commands.md new file mode 100644 index 0000000..722ef05 --- /dev/null +++ b/docs/writing/available-commands.md @@ -0,0 +1,47 @@ +# Available commands + +The FixturePlugin provides a few [symfony commands](https://symfony.com/doc/current/console.html) that you can execute. + +## Running fixtures +### Run all fixtures +```shell:no-line-numbers +bin/console fixture:load +``` + +Possible arguments: +| Argument | Description | Default Value | +| -------- | ---------------------------------------------------------- | ------------- | +| --dry | Display all fixtures that would run without executing them | false | +| --vendor | Execute also all fixtures found in the vendor directory | false | + +### Run a specific fixture +```shell:no-line-numbers +bin/console fixture:load:single {FixtureName} +``` + +Possible arguments: +| Argument | Description | Default Value | +| ------------------- | ---------------------------------------------------------- | ------------- | +| --dry | Display all fixtures that would run without executing them | false | +| --vendor | Execute also all fixtures found in the vendor directory | false | +| --with-dependencies | Also execute all dependencies recursively | false | +| -w | Alias for `--with-dependencies` | false | + +### Run a fixture group +```shell:no-line-numbers +bin/console fixture:load:group {GroupName} +``` + +Possible arguments: +| Argument | Description | Default Value | +| -------- | ---------------------------------------------------------- | ------------- | +| --dry | Display all fixtures that would run without executing them | false | +| --vendor | Execute also all fixtures found in the vendor directory | false | + +## Helper commands +### Get random UUID +```shell:no-line-numbers +bin/console fixture:uuid +``` + +This command just returns a valid, random UUID. \ No newline at end of file diff --git a/docs/writing/dependencies-prioritization.md b/docs/writing/dependencies-prioritization.md new file mode 100644 index 0000000..5f70085 --- /dev/null +++ b/docs/writing/dependencies-prioritization.md @@ -0,0 +1,68 @@ +# Dependencies & Prioritization + +## Dependencies between Fixtures +Each fixture can optionally define dependencies on other fixtures. A common example is creating customer groups before customers or properties before products. + +Dependencies can be specified by overriding the `dependsOn` method in the fixture itself. + +```php +taxRepository->create( // [!code ++] + [ // [!code ++] + 'taxRate' => 90, // [!code ++] + 'name' => 'Ultra high tax', // [!code ++] + 'position' => 4, // [!code ++] + ], // [!code ++] + Context::createDefaultContext() // [!code ++] + ); // [!code ++] + } +} +``` + +Execute the fixtures again: +```shell:no-line-numbers +bin/console fixture:load +``` + +After successfully executing the command, you should now have an additional tax rate of 90%! + +## Better use upsert instead of create +We have one problem with our fixture. Try to run the fixtures again: + +```shell:no-line-numbers +bin/console fixture:load +``` + +We now have two tax entities, each with a rate of 90%. This means that every time we execute the fixtures, a new tax entity is created without cleaning the old one! + +We have multiple ways to handle this situation. For example, we could remove the old tax rate before creating a new one, or check if it exists and then update it. Fortunately, Shopware already has a built-in method for handling these cases: [upsert](https://developer.shopware.com/docs/guides/plugins/plugins/framework/data-handling/writing-data.html#upserting-data)! + +The `upsert` method requires a fixed ID. It will check if an entity with the same ID exists and update it. If it does not exist, it will create a new entity with that ID. + +Applying this to our fixture, it will look something like this: + +```php +taxRepository->create( // [!code --] + $this->taxRepository->upsert( // [!code ++] + [ + 'id' => '0190210cf21273af9cb04437e6787605', // [!code ++] + 'taxRate' => 90, + 'name' => 'Ultra high tax', + 'position' => 4, + ], + Context::createDefaultContext() + ); + } +} +``` + +:::tip +To get a random UUID that can be used for these cases, you can use the `bin/console fixture:uuid` command, which prints a random UUID in the console. +::: + +If we now manually remove the old tax rates and execute the fixtures multiple times, we will only have one additional tax rate of 90% :tada: + +```shell:no-line-numbers +bin/console fixture:load +bin/console fixture:load +``` + +## Next Steps +Congratulations! You've written your first fixture :tada: + +Here are some more useful resources to help you continue: +- [See dependencies & prioritization to even better manage your fixtures](/writing/dependencies-prioritization.html) +- [All of our helper methods to make your life easier](/writing/fixture-helper) +- [A lot of example fixture to help you get started](/examples/index) diff --git a/docs/writing/fixture-helper.md b/docs/writing/fixture-helper.md new file mode 100644 index 0000000..b1909b9 --- /dev/null +++ b/docs/writing/fixture-helper.md @@ -0,0 +1,62 @@ +# Fixture Helper + +Often in fixtures, you need to access specific entities in the database, delete old records, or create new ones. Writing all these database queries multiple times can become quite cumbersome. To simplify this, we have integrated a handy helper class: `FixtureHelper`. + +The `FixtureHelper` provides numerous small methods to fetch data from the database or write records. + +:::warning +The fixture helpers are designed to be most convenient for local development and fixtures. They are not intended for use in production code! +::: + +## How to use +The `FixtureHelper` is already included in any fixture (since version 3). You can simply access the fixture helper: + +```php +helper->SalesChannel()->getStorefrontSalesChannel(); // [!code focus] + } +} +``` + +If you are using version 2 or want to use the `FixtureHelper` in other cases (like tests), you can use [dependency injection](https://symfony.com/doc/current/components/dependency_injection.html) like any other [Symfony service](https://symfony.com/doc/current/service_container.html): + +```php +helper->SalesChannel()->getStorefrontSalesChannel(); // [!code focus] + } +} +``` + +## Available helpers +Below is a list of all available helper categories. Please refer to the documentation for each category to see all the available methods: + +| Helper | Description | Documentation | +| ----------------- | ------------------------------------------------------- | ----------------------------------------------------- | +| Utility Methods | Some general methods to help writing fixtures | [Utility Methods](/helpers/utility) | +| Media | Methods to interact with the media entities | [Media Helpers](/helpers/media) | +| Category | Methods to interact with the categoriy entities | [Category Helpers](/helpers/category) | +| Sales Channel | Methods to interact with the sales channel entities | [Sales Channel Helpers](/helpers/sales-channel) | +| Salutation | Methods to interact with the salutation entities | [Salutation Helpers](/helpers/salutation) | +| CMS | Methods to interact with the cms page entities | [CMS Helpers](/helpers/cms) | +| Payment Method | Methods to interact with the payment method entities | [Payment Method Helpers](/helpers/payment-method) | +| Shipping Method | Methods to interact with the shipping method entities | [Shipping Method Helpers](/helpers/shipping-method) | +| Language & Locale | Methods to interact with the language & locale entities | [Language & Locale Helpers](/helpers/language-locale) | +| Currency | Methods to interact with the currency entities | [Currency Helpers](/helpers/currency) | +| Tax | Methods to interact with the tax entities | [Tax Helpers](/helpers/tax) | +| Database | Methods to interact with the database itself | [Database Helpers](/helpers/database) | + +Each helper category provides specialized methods to make working with different aspects of your Shopware setup easier and more efficient. diff --git a/docs/writing/groups.md b/docs/writing/groups.md new file mode 100644 index 0000000..232beee --- /dev/null +++ b/docs/writing/groups.md @@ -0,0 +1,56 @@ +# Grouping +Fixtures can be assigned to one or more groups. Groups allow fixtures to be executed together without executing any other fixtures outside the group. + +## Assign groups to fixtures +To assign one or more groups to any fixture, you need to override the `groups` method in the fixture itself: + +```php +Warning +:::info +Please see the chapter about [Dependencies & Prioritization](/writing/dependencies-prioritization) to learn more about dependencies between fixtures. +::: + +When a fixture has dependencies and is part of a group, all dependencies must also be in the same group(s). If any dependency cannot be resolved within the same group, the command will throw an error! + +## Use cases +Here are a few use cases that we at [basecom](https://basecom.de) implement within our fixtures. This list is not exhaustive, and if you have more use cases, please let us know so we can add them! + +### Groups for specific environments +We often use groups to specify fixtures that should only run in a specific environment. For example, we frequently have a `staging` group. These fixtures will only be executed in the staging environment (as part of our deployment). We use this to configure settings, create demo accounts, and more, making testing simpler. + +Sometimes we even have a `production` group. In this group, we put fixtures to create email template types or custom entities. Without the FixturePlugin, this was often done via [Migrations](https://developer.shopware.com/docs/guides/plugins/plugins/plugin-fundamentals/database-migrations.html) or [plugin lifecycle methods](https://developer.shopware.com/docs/guides/plugins/plugins/plugin-fundamentals/plugin-lifecycle.html), but we find it quite convenient to have it all in one place. + +### Groups for specific features +When developing larger features, you'll often end up with a lot of different fixtures. For example, implementing the Product Detail Page (PDP) might require at least one product, reviews, property groups and options, prices, tax information, and more. + +We recommend splitting this into multiple smaller fixtures but assigning them all to the same group, such as `pdp`. This way, if any developer needs to work on the PDP, they can just execute the `pdp` fixtures and have all the necessary data to work on it. + +These groups can also be used in [automated tests](/writing/phpunit-tests), so you don't need to load all fixtures when testing the PDP or any other feature. diff --git a/docs/writing/phpunit-tests.md b/docs/writing/phpunit-tests.md new file mode 100644 index 0000000..699dac7 --- /dev/null +++ b/docs/writing/phpunit-tests.md @@ -0,0 +1,116 @@ +# PHPUnit & Tests + +In addition to running fixtures via [console command](https://symfony.com/doc/current/console.html), you can also execute fixtures within your PHPUnit tests. For this purpose, we provide a trait called `FixtureTrait`, which contains all the necessary methods to run fixtures. + +## Run specific fixtures +To run specific fixtures, simply add the trait to your test and call the `runSpecificFixtures` method: + +```php +use Basecom\FixturePlugin\FixtureTrait; // [!code focus] + +class MyTest extends TestCase { + use FixtureTrait; // [!code focus] + + public function testThatSomethingWorks(): void { + $this->runSpecificFixtures(['CustomerFixture', 'ProductFixture']); // [!code focus] + } +} +``` + +Optionally, you can also specify that all [dependencies](/writing/dependencies-prioritization) of the given fixtures should be loaded as well by setting the second argument to `true`: + +```php +use Basecom\FixturePlugin\FixtureTrait; + +class MyTest extends TestCase { + use FixtureTrait; + + public function testThatSomethingWorks(): void { + $this->runSpecificFixtures(['CustomerFixture', 'ProductFixture']); // [!code --] + $this->runSpecificFixtures(['CustomerFixture', 'ProductFixture'], true); // [!code ++] + } +} +``` + +## Run a single fixture +To run a single fixture, simply add the trait to your test and call the `runSingleFixture` method: + +```php +use Basecom\FixturePlugin\FixtureTrait; // [!code focus] + +class MyTest extends TestCase { + use FixtureTrait; // [!code focus] + + public function testThatSomethingWorks(): void { + $this->runSingleFixture('CustomerFixture'); // [!code focus] + } +} +``` + +Optionally, you can also specify that all [dependencies](/writing/dependencies-prioritization) of the given fixture should be loaded as well by setting the second argument to `true`: + +```php +use Basecom\FixturePlugin\FixtureTrait; + +class MyTest extends TestCase { + use FixtureTrait; + + public function testThatSomethingWorks(): void { + $this->runSingleFixture('CustomerFixture'); // [!code --] + $this->runSingleFixture('CustomerFixture', true); // [!code ++] + } +} +``` + +## Run a fixture group +To run a whole fixture group, simply add the trait to your test and call the `runFixtureGroup` method: + +```php +use Basecom\FixturePlugin\FixtureTrait; // [!code focus] + +class MyTest extends TestCase { + use FixtureTrait; // [!code focus] + + public function testThatSomethingWorks(): void { + $this->runFixtureGroup('PDP'); // [!code focus] + } +} +``` + +Optionally, you can also specify that all [dependencies](/writing/dependencies-prioritization) of the given fixture group should be loaded as well by setting the second argument to `true`: + +```php +use Basecom\FixturePlugin\FixtureTrait; + +class MyTest extends TestCase { + use FixtureTrait; + + public function testThatSomethingWorks(): void { + $this->runFixtureGroup('PDP'); // [!code --] + $this->runFixtureGroup('PDP', true); // [!code ++] + } +} +``` + +## More complex scenarios +If you want or need more fine control over which fixtures run, you can use the `runFixtures` method. This method takes a `FixtureOption` parameter, which can be freely configured: + +```php +use Basecom\FixturePlugin\FixtureTrait; // [!code focus] +use Basecom\FixturePlugin\FixtureOption; // [!code focus] + +class MyTest extends TestCase { + use FixtureTrait; // [!code focus] + + public function testThatSomethingWorks(): void { + $this->runFixtures(new FixtureOption( // [!code focus] + groupName: 'PDP', // [!code focus] + fixtureNames: ['CategoryFixture', 'AnotherFixture'], // [!code focus] + withDependencies: true, // [!code focus] + withVendor: true // [!code focus] + )); // [!code focus] + } +} +``` + +All these parameters are combinable and allow for a very specific execution of fixtures. All other methods are simply alias methods for this one method with preconfigured options. diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index bea17fa..0000000 --- a/package-lock.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "bsc-template-plugin", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "bsc-template-plugin", - "version": "1.0.0", - "license": "Standard copyright", - "devDependencies": { - "prettier": "^3.2.5" - } - }, - "node_modules/prettier": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - } - } -} diff --git a/package.json b/package.json index caf1091..6c34391 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,14 @@ { - "name": "bsc-template-plugin", - "version": "1.0.0", - "main": "index.js", - "license": "Standard copyright", + "name": "sw6-fixture-plugin", "private": true, + "type": "module", "devDependencies": { - "prettier": "^3.2.5" + "prettier": "^3.2.5", + "vitepress": "^1.2.3" + }, + "scripts": { + "docs:dev": "vitepress dev docs", + "docs:build": "vitepress build docs", + "docs:preview": "vitepress preview docs" } -} +} \ No newline at end of file diff --git a/src/Command/UuidCommand.php b/src/Command/UuidCommand.php new file mode 100644 index 0000000..9264183 --- /dev/null +++ b/src/Command/UuidCommand.php @@ -0,0 +1,25 @@ +text(Uuid::randomHex()); + + return Command::SUCCESS; + } +} diff --git a/src/Utils/LanguageAndLocaleUtils.php b/src/Utils/LanguageAndLocaleUtils.php index 7ccefe3..19a7193 100644 --- a/src/Utils/LanguageAndLocaleUtils.php +++ b/src/Utils/LanguageAndLocaleUtils.php @@ -4,7 +4,6 @@ namespace Basecom\FixturePlugin\Utils; -use Doctrine\Inflector\Language; use Shopware\Core\Framework\Context; use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository; use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria; @@ -107,11 +106,11 @@ public function getCountry(string $countryIso): ?CountryEntity /** * Return a specific snippet set by its country's ISO code or null if its was not found. */ - public function getSnippetSet(string $countryCodeIso): ?SnippetSetEntity + public function getSnippetSet(string $localeIsoCode): ?SnippetSetEntity { - return once(function () use ($countryCodeIso): ?SnippetSetEntity { + return once(function () use ($localeIsoCode): ?SnippetSetEntity { $criteria = (new Criteria())->addFilter( - new EqualsFilter('iso', $countryCodeIso), + new EqualsFilter('iso', $localeIsoCode), )->setLimit(1); $criteria->setTitle(sprintf('%s::%s()', __CLASS__, __FUNCTION__));