diff --git a/.github/scripts/format-adrs.ts b/.github/scripts/format-adrs.ts index fd4fcbaaf..5e444fcf3 100644 --- a/.github/scripts/format-adrs.ts +++ b/.github/scripts/format-adrs.ts @@ -5,6 +5,7 @@ import * as path from "https://deno.land/std@0.145.0/path/mod.ts"; const formattingPromises = []; for await (const entry of walk("./resources/references/adr")) { if (entry.isDirectory) continue; + if (!entry.path.endsWith('.md')) continue; if (path.basename(entry.path).startsWith('_')) continue; if (path.basename(entry.path) === 'index.md') continue; if (path.basename(entry.path) === 'README.md') continue; diff --git a/.github/scripts/format-code-guidelines.ts b/.github/scripts/format-code-guidelines.ts index 06b09a906..51d93ee82 100644 --- a/.github/scripts/format-code-guidelines.ts +++ b/.github/scripts/format-code-guidelines.ts @@ -5,6 +5,7 @@ import * as path from "https://deno.land/std@0.145.0/path/mod.ts"; const formattingPromises = []; for await (const entry of walk("./resources/guidelines/code/core")) { if (entry.isDirectory) continue; + if (!entry.path.endsWith('.md')) continue; if (path.basename(entry.path).startsWith('_')) continue; if (path.basename(entry.path) === 'index.md') continue; if (path.basename(entry.path) === 'README.md') continue; @@ -14,6 +15,10 @@ for await (const entry of walk("./resources/guidelines/code/core")) { await Promise.allSettled(formattingPromises); function addHint(buffer, filePath) { + if (filePath.includes('/adr/assets/')) { + return buffer; + } + buffer += '\n'; buffer += '::: info\n'; buffer += 'This document represents core guidelines and has been mirrored from the core in our Shopware 6 repository.\n'; diff --git a/.github/workflows/spellcheck.yml b/.github/workflows/spellcheck.yml index 168585c5f..ee2e2eb77 100644 --- a/.github/workflows/spellcheck.yml +++ b/.github/workflows/spellcheck.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: rojopolis/spellcheck-github-actions@0.41.0 + - uses: rojopolis/spellcheck-github-actions@0.43.0 name: Spellcheck with: config_path: .spellcheck.yml diff --git a/.gitignore b/.gitignore index d48c759d6..daca60d87 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .idea -.vscode \ No newline at end of file +.vscode +/dictionary.dic \ No newline at end of file diff --git a/.wordlist.txt b/.wordlist.txt index 5d4a2ec9e..f9453eca4 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -1,6 +1,13 @@ +ACL +ACLs +ADDR +ADR +ADRs +AOF +API's +APIs AbstractCaptcha AbstractStockUpdateFilter -accel AccountEditOrderPage AccountGuestLoginPage AccountLoginPage @@ -10,108 +17,60 @@ AccountOverviewPage AccountPaymentMethodPage AccountProfilePage AccountRecoverPasswordPage -acl Acl -ACL AclContextProvider AclGrantContext -ACLs ActionButton ActionButtons ActivateContext -activateShopwareTheme AdapterFactory AddCustomerTagActionTest -ADDR AddressBookWidget AddressDetailPage AddressListingPage +AdminQueueWorker +AdminWorker Adminer AdministrationNewField AdministrationNewModule -AdminQueueWorker -AdminWorker -adr -ADR -ADRs Afile AfterLineItemAddedEvent AfterLineItemQuantityChangedEvent AfterLineItemRemovedEvent -afterSort -ag AggregationResultCollection -ajax AjaxModalPlugin Algolia AllowEmptyString AllowHtml AlwaysValidRule -amqp Analytics AndRule -anonymization -anonymize -anonymized -antipattern -AOF -api ApiAware ApiContext ApiController -apiKey ApiKey -API's -APIs ApiService Aplaceholder AppRefundHandler AppScripts AppServer AppSystem -appVersion -args -arrayfacade ArrayFacade -async -AsynchronousPaymentHandlerInterface AsyncPaymentTransactionStruct -atomicity +AsynchronousPaymentHandlerInterface AuditLogValueEntity -auth AuthenticationIdentityLoader -autocompletion -autogenerate -autogenerated -autoload -autoloaded -autoloader -autoloading -autom -autoprefixer -autowire -autowiring AvailableCombinationLoader AvgResult -awaitAndCheckNotification -axios B2B Component B2B Components B2B Suite -backend +BBundle +BDD +BITV Backend -backends -backface -backoff -backported -bAcl -bAjaxPanel BaseContext BasicExample -bAuditLog -bAuth -BBundle -BDD BeforeCartMergeEvent BeforeLineItemAddedEvent BeforeLineItemQuantityChangedEvent @@ -123,76 +82,46 @@ BeforeShopDeletionEvent BillingCountryRule BillingStreetRule BillingZipCodeRule -binlog Bitbucket -BITV -blackbox -blackfire Blackfire BlacklistRule BlacklistRuleField BlobField -blockquote Blockquote -blockquotes Blockquotes -bLogin -bolded -bool -boolean -booleans BoolField -bottleJs -bottleJS BottleJS -bourgau -bPlatform -brainer -bRestApi -browserslist -bruteforce -bServiceExtension -bTemplateExtension -bugfix -bugfixes -bundler BusinessEvent BusinessEventCollector -buyable -cacheable +CDN +CDNs +CHANGELOG +CKEditor +CLI +CMS +CORS +CPUs +CSP +CSPs +CSRF +CSV CachedProductListingRouteTest -cacheinvalidatorfacade -cacheKey -cachix Cachix Caddy Caddyfile -calculatedCheapestPrice -calculatedPrice CalculatedPrice CalculatedPriceField -calculatedPrices -callables -camelcase -camelCase -caniuse -capitalizeString -capsulate -captcha Captcha Captchas -captureId CartAmountRule CartConvertedEvent CartCreatedEvent CartDataCollection CartDeletedEvent -cartfacade CartHasDeliveryFreeItemRule CartLoadedEvent CartMergedEvent CartPrice -cartpricefacade CartPriceFacade CartPriceField CartPromotionsCollector @@ -201,27 +130,15 @@ CartVerifyPersistEvent CartWeightRule CascadeDelete CashRounding -catchable -catched CategoryRoute -CDN -CDNs CentOS Cerebro -cetera Chai ChangeCustomerSpecificFeaturesAction ChangeEmployeeStatusAction -changelog Changelog -CHANGELOG -changelogs Changelogs -changeset -changesets -chargeback Chargeback -checkboxes CheckoutCartPage CheckoutCartPageLoadedEvent CheckoutConfirmPage @@ -237,383 +154,1045 @@ ChildCount ChildCountField ChildrenAssociation ChildrenAssociationField -ci -CKEditor -classname -cleanUpPreviousState -clearTypeAndCheck -cli -CLI -clickContextMenuItem -clickMainMenuItem ClientInterface -cloneDeep Cloudflare Cmd -cms -CMS CmsPage -cmss -cmsService -codebase -codeblock -codeblocks -codereview Codestyle -colorpicker CommercialB CommercialBundle -compatability ComponentFactory -componentSectionRenderer -composable Composables -config -configComponent ConfigJson ConfigJsonField -configs -configurator -Configurator ConfigValidator -confirmUrl +Configurator ConfirmUrlAware ConfirmUrlStorer -const -const's ContactController -contactFormData ContactFormDataAware ContactFormDataStorer ContactRole ContainerBuilder -containerfacade ContainerFacade ContentsAware ContentsStorer ContextResolver ContextTokenAware ContextTokenStorer -control CookiePermission -copyable -copyToClipboard -cors -CORS CountryStateDataPagelet -CPUs -createActionResponse -createCategoryFixture -createCmsFixture -createCustomerFixture +CreateFromTrait +CreateTagAction CreatedAt CreatedAtField CreatedBy CreatedByField -createDefaultContext -createDefaultFixture -CreateFromTrait -createGuestOrder -createId -createLanguageFixture -createProductFixture -createPropertyFixture -createSalesChannelFixture -createShippingFixture -createSnippetFixture -CreateTagAction -createValidatorDefinition CredentialsBuilder CredentialsEntity CriteriaEvent CriteriaParser CriteriaTest -cron Cronjobs CrossSellingDataSet -cryptographic -CSP -CSPs -csrf -CSRF -css -CSV Ctrl CurrencyRule CustomAppAware CustomAppEvent CustomAppStorer CustomEntityKernelLoader -customerAware +CustomField CustomerAware CustomerBeforeLoginEvent -customerGroup -customerGroupAware CustomerGroupAware CustomerGroupRegistrationPage CustomerGroupRule CustomerGroupStorer -customerHasFeature CustomerLoginEvent CustomerNumberRule -customerRecovery CustomerRecoveryAware CustomerRecoveryStorer CustomerStorer CustomerTagRule -CustomField -customFields -customizability -customizable -customizations -customizer -cyclus +DAL +DBAL +DDL +DESC +DIC +DIC EntityRepository +DOM +DOMPurify +DS +DSGVO +DSN +DSR +DTO +DTOs +DX Daily.co -dailymotion Dailymotion -dal Dal -DAL -dannorth -dasistweb DataAbstractionLayer DataAware -datadog -Datadog DataResolver -dataSelection DataSelection -dataset -dataSet DataSet -datasets DataSets DataStorer +Datadog DateField -datepicker -Datepicker DateRangeRule -datetime DateTime DateTimeField +Datepicker DaysSinceLastOrderRule -DBAL -DDL -de -debounce DebugStack -decoratable -decrementing Decrypts -deepCopyObject -deepMergeObject -defaultConfig -defaultValue DelayAction -delayAware DelayAware DelegatingLoader -deletable Deleter +Deno +Denormalization +Denylist +Dependabot +DependencyInjection +Deployer +Deprecations +Deutsch +DevOps +Devenv +DeviceHelper +Devops +Devtool +DifferentAddressesRule +Differentiator +DirectoryLoader +Direnv +DiscountFacade +Dockerfile +Dockware +DomainException +DomainExceptions +DynamoDB +ENUM +ENUMS +EOL +ERP +ESLint +EcmaScript +ElasticSearch +ElasticsearchDefinition +ElasticsearchEntityAggregator +ElasticsearchEntitySearcher +ElasticsearchProductDefinition +EmailAware +EmailField +EmailStorer +EmployeeAware +EmployeeOfBusinessPartnerRule +EmployeeOrderRule +EmployeeRoleRule +EmployeeStatusRule +Enqueue +EntityCollection +EntityContainerEvent +EntityDefinition +EntityExtension +EntityNotFound +EntityRepository +EntitySearchResult +EntityWrittenContainerEvent +EntityWrittenEvent +Enum +Enums +EqualsAny +ErrorsFacade +EventListener +EventSubscriberInterface +Everytime +ExampleController +ExampleDefinition +ExampleDescription +ExampleEvent +ExampleExtensionDefinition +ExampleHandler +ExamplePagelet +ExamplePageletLoadedEvent +ExamplePageletLoader +ExamplePlugin +ExampleTranslationDefinition +ExcludeMultiWarehouseStockUpdateFilter +Extensibility +ExtensionAPI +FPM +FQCN +FastRoute +Fastly +Fastorder +FieldCollection +FieldSerializer +FileLocator +FileReader +Filesystem +Fk +FkField +FloatField +FlowAction +FlowBuilder +FlowBuilderActionApp +FlowBuilderTriggerApp +FlowDispatcher +FlowEventAware +FlowExecutor +FlowStore +FlowStorer +Flysystem +Fontawesome +FooterPagelet +FrameworkBundle +FroshDevelopmentHelper +FroshPluginUploader +Fullstack +GDPR +GIFs +GenericPage +GenericPageLoader +GitLab +Github +GlobFileLoader +GmbH +GoodsCountRule +GoodsPriceRule +GoogleReCaptchaV +Grafana +Grantable +GridHelper +GuestWishlistPage +GuestWishlistPagelet +HMAC +Homebrew +Hono +HookClasses +HookExecutor +HowTos +IDEs +IPV +IPv +IdField +IdSearchResult +Ideate +Iframe +Inclusivity +IndexerService +Init +Initialisms +IntField +IntelliSense +InterfaceHooks +IsCompanyRule +IsEmployeeRule +IsNewCustomerRule +ItemFacade +ItemsFacade +JSON +JVM +JWT +JavaScript +JestJS +JetBrains +Jira +Jit +Jonge +JsonField +JsonResponse +KV +KeyDB +Kibana +LONGTEXT +LUA +LandingPage +LastNameRule +Lerna +Lifecycle +LineItemClearanceSaleRule +LineItemCreationDateRule +LineItemCustomFieldRule +LineItemDimensionHeightRule +LineItemDimensionLengthRule +LineItemDimensionWeightRule +LineItemDimensionWidthRule +LineItemFactoryRegistry +LineItemGroupRule +LineItemHandler +LineItemInCategoryRule +LineItemIsNewRule +LineItemList +LineItemListPriceRule +LineItemOfManufacturerRule +LineItemOfTypeRule +LineItemPromotedRule +LineItemPropertyRule +LineItemPurchasePriceRule +LineItemReleaseDateRule +LineItemRemovedEvent +LineItemRule +LineItemTagRule +LineItemTaxationRule +LineItemTotalPriceRule +LineItemUnitPriceRule +LineItemWithQuantityRule +LineItemWrapperRule +LineItemsInCartCountRule +LineItemsInCartRule +ListField +ListingPrice +ListingPriceField +LoaderResolver +LockedField +LogEntry +Logfiles +LoggingService +LoginContextService +LoginRequired +LongText +LongTextField +Lychee +MACOSX +MRs +MVC +MailAware +MailHog +MailService +MailStorer +Mailcatcher +Mailhog +MaintenancePage +ManufacturerAttributeDataSet +ManyToMany +ManyToManyAssociation +ManyToManyAssociationField +ManyToManyId +ManyToManyIdField +ManyToOne +ManyToOneAssociation +ManyToOneAssociationField +MediaDataSelection +MediaDataSet +MediaFolderDataSet +MemcachedSessionHandler +MenuOffcanvasPagelet +Mercure +MessageAware +MessageQueue +MessageStorer +MeteorAdminSDK +Methodize +Middleware +MigrationCollection +Minio +Mixin +Mixins +Modularity +ModuleFactory +MongoDbSessionHandler +Monolog +Monorepo +Monorepos +MoveShopPermanently +MultiWarehouse +MyExampleApp +MyExtension +MyPlugin +MyTestClass +MyTestInterface +NPM +NameAware +NameStorer +NavigationPage +NelmioCorsBundle +NewFeature +NewRelic +NewsletterRecipientAware +NewsletterRecipientStorer +Nginx +NixOS +NoSQL +Noback +NodeJS +NotFoundHttpException +NotRule +NullObject +Nullsafe +Nuxt +Nvidia +OAuth +OPENSEARCH +ORM +ORMs +OTEL +OTLP +ObjectField +ObjectType +OffCanvas +OffcanvasCartPageLoadedEvent +OldFeature +OneToMany +OneToManyAssociation +OneToManyAssociationField +OneToOne +OneToOneAssociation +OneToOneAssociationField +OpenAPI +OpenApi +OpenSSH +OpenSSL +OpenSearch +OpenTelemetry +Openapi +Opensearch +Opensearch's +OrRule +OrderAware +OrderCountRule +OrderEntity +OrderEvents +OrderLineItem +OrderLineItemEntity +OrderStorer +OrderTransaction +OrderTransactionAware +OrderTransactionCapture +OrderTransactionCaptureCollection +OrderTransactionCaptureEntity +OrderTransactionCaptureRefund +OrderTransactionCaptureRefundEntity +OrderTransactionCaptureRefundPosition +OrderTransactionCaptureRefundPositionCollection +OrderTransactionEntity +OrderTransactionRefundCollection +OrderTransactionStorer +PHPStan +PHPStorm +PHPUnit +PHPunit +PII +POC +POS +PRs +PSH +PSP +PSR +PWA +PaaS +Paas +Packagist +PageEvent +PageLoaded +PageLoadedEvent +PageLoadedEvents +PageLoader +PageLoader structs +PageType +Pagelet +PageletLoader +Pagelets +Pageloaders +ParentAssociation +ParentAssociationField +ParentFk +ParentFkField +PasswordField +PaymentGatewayApp +PaymentHandlerIdentifierSubscriber +PaymentMethod +PaymentMethodRoute +PaymentMethodRule +PaymentRefundHandlerInterface +PaymentRefundProcessor +PdoSessionHandler +Percona +Persistable +PhpRedis +PhpStan +PhpUnit +PluginManager +PositionID +PositionIDs +PositionIdentifier +PostInstall +PostMessage +PostUpdate +PreWriteValidationEvent +Predis +Preload +Premapping +PreparedPaymentHandlerInterface +Preselect +PriceCollectionFacade +PriceDefinition +PriceDefinitionField +PriceFacade +PriceField +PriceFieldSerializer +PrimaryKey +ProductAttributeDataSet +ProductAware +ProductCartProcessor +ProductCartTest +ProductCategoryDefinition +ProductController +ProductCountRouteResponse +ProductDataSelection +ProductDataSet +ProductListRoute +ProductManufacturerDefinition +ProductMedia +ProductMediaDefinition +ProductNumber +ProductOptionRelationDataSet +ProductPage +ProductPriceAttributeDataSet +ProductPriceCalculator +ProductPropertyRelationDataSet +ProductQuickViewWidget +ProductReviewsWidget +ProductSearchBuilder +ProductStorer +ProductSubscriber +ProductUpdater +ProductVisibility +ProductWarehouse +ProductWarehouses +ProductsFacade +Profiler +PropertyGroupOptionDataSet +ProseMirror +Prosemirror +Pseudocode +Punctuations +Quickstart +QuillJS +RDB +README +RabbitMQ +RabbitMq +Readonly +RecipientsAware +RecipientsStorer +RecurringPaymentHandlerInterface +Redict +RedirectResponse +ReferenceVersion +ReferenceVersionField +RefundPaymentHandlerInterface +RegistrationCompletedEvent +RegistrationService +Reindexes +ReinstallApps +RemoteAddress +RemoteAddressField +Repo +RepositoryIterator +ResetUrlAware +ResetUrlStorer +RestAPI +RestrictDelete +ReverseInherited +ReviewFormDataAware +ReviewFormDataStorer +Reviewdog +Roadmap +RouteResponse +RuleConditionService +RuntimeException +SCSS +SDK +SDK's +SDKs +SEO +SEOs +SFTP +SHA +SKEs +SMS +SMTP +SPA's +SPAs +SQS +SSHes +SSL +STP +SVG +SVGs +SaaS +Sales Rooms +SalesAgent +SalesChannel +SalesChannelAware +SalesChannelContext +SalesChannelContextCreatedEvent +SalesChannelContextResolvedEvent +SalesChannelContextRestoredEvent +SalesChannelContextRestorerOrderCriteriaEvent +SalesChannelId +SalesChannelProductEntity +SalesChannelRule +SameSite +ScalarValuesAware +ScalarValuesStorer +ScheduledTask +ScriptEventRegistry +SearchCriteria +SearchPage +SearchRanking +SearchWidget +SecretKey +Sendfile +SeoUrlRoute +SeoUrlTemplate +SetNullOnDelete +ShippingCountryRule +ShippingMethodPriceCollector +ShippingMethodRoute +ShippingMethodRule +ShippingStreetRule +ShippingZipCodeRule +ShopActivatedEvent +ShopDeactivatedEvent +ShopDeletedEvent +ShopNameAware +ShopNameStorer +Shopware +Shopware's +SimpleHttpClient +Sinon +SitemapPage +SnippetFileInterface +SomeCoreClassTest +SonarQube +Sonarcube +StackHero +StackOverflow +Stackhero +StateMachineRegistry +StateMachineState +StateMachineStateEntity +StateMachineStateField +StatesFacade +StaticEntityRepository +StockUpdate +StockUpdateFilterProvider +StockUpdater +Storable +StorableFlow +StoreApiResponse +StoreApiRoute +StorefrontController +StorefrontResponse +Storer +StringField +StringFields +Struct +SubjectAware +SubjectStorer +Subprocessor +SuggestPage +SwagAdvDevBundle +SwagB +SwagBasicExample +SwagBasicExampleTheme +SwagDigitalSalesRooms +SwagMigrationBundleExample +SwagMyPlugin +SwagMyPluginSW +Symfony +Symfony's +SyncApi +SynchronousPaymentHandlerInterface +Synopsys +TCP +TLS +TTL +TaxProvider +TaxProviderStruct +TaxProviders +TemplateDataAware +TemplateDataStorer +TemplateNamespaceHierarchyBuilder +TestCase +TestStockUpdateFilter +TimeRangeRule +TinyMCE +TipTap +TipTap's +ToMany +ToOne +Tooltips +TransactionalAction +TranslatedField +TranslationDataSet +TranslationsAssociation +TranslationsAssociationField +TreeBreadcrumb +TreeBreadcrumbField +TreeLevel +TreeLevelField +TreePath +TreePathField +TreeSelect +TriggerReload +TwigJS +TypeError +TypeError's +TypeScript +UI +UML +USD +UUID +UUIDs +UUIDv +UX +Unassigning +UninstallApps +UnitCollection +UnitEntity +UnitTests +UnoCSS +Unregistering +Untrusted +UpdateContext +UpdateHtaccess +UpdatedAt +UpdatedAtField +UpdatedBy +UpdatedByField +UpperCamelCase +Upserting +UrlAware +UrlStorer +UserAware +UserStorer +Util +Utils +Uuid +VARCHAR +VCL +VCS +VM +VSCode +Validator +Valkey +Vercel +VersionDataPayload +VersionDataPayloadField +VersionField +VirtualHosts +Vitepress +Vitest +Vue +Vue's +VueJS +VueJs +VueX +Vuei +Vuex +WCAG +WSL +WarehouseGroup +WarehouseGroups +WebKit +WebSocket +Webhook +Webkit +Webpack +Webserver +WeekdayRule +WhitelistRule +WhitelistRuleField +WishlistPage +WishlistWidget +WriteEvents +WriteProtected +XDebug +XHR +XKey +XLIFF +XPath +XQuartz +XSS +XVFB +Xdebug +XmlHttpRequest +XmlUtils +XorRule +YYYY +YamlFileLoader +ZSH +accel +acl +activateShopwareTheme +adr +afterSort +ag +ajax +amqp +anonymization +anonymize +anonymized +antipattern +api +apiKey +appVersion +args +arrayfacade +async +atomicity +auth +autocompletion +autogenerate +autogenerated +autoload +autoloaded +autoloader +autoloading +autom +autoprefixer +autowire +autowiring +awaitAndCheckNotification +axios +bAcl +bAjaxPanel +bAuditLog +bAuth +bLogin +bPlatform +bRestApi +bServiceExtension +bTemplateExtension +backend +backends +backface +backoff +backported +binlog +blackbox +blackfire +blockquote +blockquotes +bolded +bool +boolean +booleans +bottleJS +bottleJs +bourgau +brainer +browserslist +bruteforce +bugfix +bugfixes +bundler +buyable +cacheKey +cacheable +cacheinvalidatorfacade +cachix +calculatedCheapestPrice +calculatedPrice +calculatedPrices +callables +camelCase +camelcase +caniuse +capitalizeString +capsulate +captcha +captureId +cartfacade +cartpricefacade +catchable +catched +cetera +changelog +changelogs +changeset +changesets +chargeback +checkboxes +ci +classname +cleanUpPreviousState +clearTypeAndCheck +cli +clickContextMenuItem +clickMainMenuItem +cloneDeep +cms +cmsService +cmss +codebase +codeblock +codeblocks +codereview +colorpicker +compatability +componentSectionRenderer +composable +config +configComponent +configs +configurator +confirmUrl +const +const's +contactFormData +containerfacade +control +copyToClipboard +copyable +cors +createActionResponse +createCategoryFixture +createCmsFixture +createCustomerFixture +createDefaultContext +createDefaultFixture +createGuestOrder +createId +createLanguageFixture +createProductFixture +createPropertyFixture +createSalesChannelFixture +createShippingFixture +createSnippetFixture +createValidatorDefinition +cron +cryptographic +csrf +css +customFields +customerAware +customerGroup +customerGroupAware +customerHasFeature +customerRecovery +customizability +customizable +customizations +customizer +cyclus +dTH +dailymotion +dal +dannorth +dasistweb +dataSelection +dataSet +datadog +dataset +datasets +datepicker +datetime +de +debounce +decoratable +decrementing +deepCopyObject +deepMergeObject +defaultConfig +defaultValue +delayAware +deletable demodemo +demoshop deno -Deno -Denormalization denylist -Denylist dependencyInjection -DependencyInjection -Deployer deprecations -Deprecations dereference dereferenced -DESC describeFeatures destructuring -Deutsch dev devenv -Devenv -DeviceHelper devops -Devops -DevOps devs -Devtool devtool's devtools di -DIC -DIC EntityRepository -DifferentAddressesRule differentiator -Differentiator dir -DirectoryLoader direnv -Direnv direnv's discountfacade -DiscountFacade discoverability docblock dockware -Dockware dom -DOM -DomainException -DomainExceptions -DOMPurify -dont don'ts +dont dont's dr dragTo dropdown -DSGVO -DSN dsr -DSR -dTH -DTO -DTOs dunglas duplications -DX -DynamoDB -EcmaScript +ean ecommerce +editorconfig eg elasticsearch -ElasticSearch -ElasticsearchDefinition -ElasticsearchEntityAggregator -ElasticsearchEntitySearcher -ElasticsearchProductDefinition -EmailAware -EmailField -EmailStorer -EmployeeAware employeeId -EmployeeOfBusinessPartnerRule -EmployeeOrderRule -EmployeeRoleRule -EmployeeStatusRule enqueue -Enqueue -EntityCollection -EntityContainerEvent -EntityDefinition -EntityExtension entityIds entityName -EntityNotFound -EntityRepository -EntitySearchResult -EntityWrittenContainerEvent -EntityWrittenEvent entrypoint entrypoints enum -Enum -ENUM enums -Enums -ENUMS env envs -EOL equalsAny -EqualsAny -ERP errored errorsfacade -ErrorsFacade erros eslint -ESLint et -EventListener -EventSubscriberInterface everytime -Everytime evolvability -ExampleController -ExampleDefinition -ExampleDescription -ExampleEvent -ExampleExtensionDefinition -ExampleHandler -ExamplePagelet -ExamplePageletLoadedEvent -ExamplePageletLoader -ExamplePlugin exampler -ExampleTranslationDefinition -ExcludeMultiWarehouseStockUpdateFilter explainer extendability extensibility -Extensibility -ExtensionAPI externalReference fallbacks fastly -Fastly -Fastorder -FastRoute favicon fetchable -FieldCollection -FieldSerializer fieldset -fileinfo -FileLocator -FileReader fileSize +fileinfo filesystem -Filesystem filesystems firstname -Fk -FkField flattenDeep -FloatField -FlowAction -FlowBuilder -FlowBuilderActionApp -FlowBuilderTriggerApp -FlowDispatcher -FlowEventAware -FlowExecutor -FlowStore -FlowStorer flyout -Flysystem focussed focussing fontFamily -FooterPagelet formatters -FPM -FQCN -FrameworkBundle frankdejonge frontend frontends frontmatter -FroshDevelopmentHelper -FroshPluginUploader -Fullstack func +gRPC gd -GDPR -GenericPage -GenericPageLoader german getArrayChanges -getbootstrap getChildren getConstraints getCreationTimestamp @@ -639,39 +1218,29 @@ getScrollbarHeight getScrollbarWidth getSeoUrls getTaxes -getter -getters getTotal getType getUnit getUrls +getbootstrap +getter +getters ghcr gif -GIFs github -Github +gitignore +gitkeep gitlab -GitLab globals -GlobFileLoader -GmbH -GoodsCountRule -GoodsPriceRule -GoogleReCaptchaV goto -Grafana grantable -Grantable granularly graphviz gridActions gridColumns -GridHelper grpc -gRPC -GuestWishlistPage -GuestWishlistPagelet guid +gz gzip handleFlow hardcoded @@ -681,71 +1250,47 @@ helpText herokuapp hideCookieBar hmac -HMAC -Homebrew hono -Hono -HookClasses -HookExecutor hosters hostname -HowTos html http httpCache https hydrator +iFrame +iFrames +iOs iconv -Ideate -IDEs -IdField -IdSearchResult ified iframe -iFrame -Iframe iframes -iFrames inclusivity -Inclusivity incrementer incrementing indexActions -IndexerService infoIt ini init -Init initialisms -Initialisms initializer initializers installable instantiation integrations -IntelliSense -InterfaceHooks -IntField intl invalidations io -iOs -IPv -IPV isActive isArray isBoolean isCloseout -IsCompanyRule isDate -IsEmployeeRule isEmpty isEmptyOrSpaces isEqual isFunction -IsNewCustomerRule isNumber -iso isObject isPlainObject isPropagationStopped @@ -755,129 +1300,49 @@ isUndefined isUrl isValid isValidIp +iso itemfacade -ItemFacade itemsfacade -ItemsFacade iterable iteratively +jQuery jargons javascript -JavaScript -JestJS -JetBrains -Jira -Jit -Jonge -jQuery js +js's json -JSON jsonEncode -JsonField -JsonResponse -js's -JVM jwt -JWT kebabCase -KeyDB keyframes -Kibana -KV -LandingPage lang -LastNameRule lazysizes -Lerna libxml lifecycle -Lifecycle lifecycles lifecylce lineItem -LineItemClearanceSaleRule -LineItemCreationDateRule -LineItemCustomFieldRule -LineItemDimensionHeightRule -LineItemDimensionLengthRule -LineItemDimensionWeightRule -LineItemDimensionWidthRule -LineItemFactoryRegistry -LineItemGroupRule -LineItemHandler lineItemId -LineItemInCategoryRule -LineItemIsNewRule -LineItemList -LineItemListPriceRule -LineItemOfManufacturerRule -LineItemOfTypeRule -LineItemPromotedRule -LineItemPropertyRule -LineItemPurchasePriceRule -LineItemReleaseDateRule -LineItemRemovedEvent -LineItemRule -LineItemsInCartCountRule -LineItemsInCartRule -LineItemTagRule -LineItemTaxationRule -LineItemTotalPriceRule -LineItemUnitPriceRule -LineItemWithQuantityRule -LineItemWrapperRule linter linux -ListField -ListingPrice -ListingPriceField -LoaderResolver +localVue localhost localhost's -localVue locationID locationIDs -LockedField -LogEntry logfiles -Logfiles -LoggingService logics -LoginContextService loginRequired -LoginRequired loginViaApi -LongText -LONGTEXT -LongTextField lookups lowerCamelCase -LUA lychee -Lychee macOS mailAware -MailAware -Mailcatcher -Mailhog -MailHog -MailService -MailStorer mailTemplates -MaintenancePage makefile mandatorily -ManufacturerAttributeDataSet manufacturerId -ManyToMany -ManyToManyAssociation -ManyToManyAssociationField -ManyToManyId -ManyToManyIdField -ManyToOne -ManyToOneAssociation -ManyToOneAssociationField mapErrors martinfowler masternode @@ -886,215 +1351,91 @@ matthiasnoback maxPurchase mbstring md -MediaDataSelection -MediaDataSet -MediaFolderDataSet mediaId mediaService -MemcachedSessionHandler memoization memoized -MenuOffcanvasPagelet mercure -Mercure mergeWith -MessageAware -MessageQueue -MessageStorer -MeteorAdminSDK -Methodize middleware -Middleware middlewares -MigrationCollection +minPurchase minified minimalistic -Minio -minPurchase mixin -Mixin mixins -Mixins mocksArentStubs modifiability modularity -Modularity -ModuleFactory monday -MongoDbSessionHandler monolog -Monolog monorepo -Monorepo monorepos -Monorepos -MoveShopPermanently moz mozilla +mpn mr -MRs -MultiWarehouse -MVC -MyExampleApp myNewMethod -MyPlugin myPluginLogHandler mysql mysqldump -MyTestClass -MyTestInterface -NameAware namespace namespaces -NameStorer natively nav -NavigationPage navigations nd -NelmioCorsBundle -NewFeature newQuantity -NewRelic newsletterRecipient -NewsletterRecipientAware -NewsletterRecipientStorer -Nginx ngrok nixos -NixOS nl -Noback -NodeJS nofollow noindex noopener -NoSQL -NotFoundHttpException -NotRule npm -NPM nullable -NullObject nullsafe -Nullsafe -Nuxt -Nvidia oauth -OAuth -ObjectField -ObjectType observability oder -offcanvas -OffCanvas offCanvasCart -OffcanvasCartPageLoadedEvent +offcanvas og ok -OldFeature -OneToMany -OneToManyAssociation -OneToManyAssociationField -OneToOne -OneToOneAssociation -OneToOneAssociationField onlyAvailable onlyOnFeature onwards oop opcache -Openapi -OpenApi -OpenAPI openInitialPage +openUserActionMenu opensearch -Opensearch -OpenSearch -OPENSEARCH -Opensearch's -OpenSSH openssl -OpenSSL -OpenTelemetry -openUserActionMenu orderAware -OrderAware -OrderCountRule -OrderEntity -OrderEvents orderIds -OrderLineItem -OrderLineItemEntity -OrderStorer orderTransaction -OrderTransaction -OrderTransactionAware -OrderTransactionCapture -OrderTransactionCaptureCollection -OrderTransactionCaptureEntity orderTransactionCaptureRefund -OrderTransactionCaptureRefund -OrderTransactionCaptureRefundEntity -OrderTransactionCaptureRefundPosition -OrderTransactionCaptureRefundPositionCollection -OrderTransactionEntity -OrderTransactionRefundCollection -OrderTransactionStorer org's -ORM -ORMs -OrRule otel -OTEL otlp -OTLP oversales paas -Paas -PaaS packagist -Packagist -PageEvent +pageLoaders pagelet -Pagelet -PageletLoader pageletloaders pagelets -Pagelets -PageLoaded -PageLoadedEvent -PageLoadedEvents pageloader -PageLoader -pageLoaders -Pageloaders -PageLoader structs -PageType parallelize param params -ParentAssociation -ParentAssociationField -ParentFk -ParentFkField parsers -PasswordField -PaymentGatewayApp -PaymentHandlerIdentifierSubscriber -PaymentMethod -PaymentMethodRoute -PaymentMethodRule -PaymentRefundHandlerInterface -PaymentRefundProcessor paypal pcre pdf pdo -PdoSessionHandler -Percona performant -Persistable persister phar philippe @@ -1102,359 +1443,175 @@ php phpdoc phpdocs phpinfo -PhpRedis phpstan -PhpStan -PHPStan -PHPStorm phpunit -PhpUnit -PHPunit -PHPUnit phpunit's -PII +phpunitx pluginlogger -PluginManager png pnpm -POC pos -POS positionID -PositionID -PositionIdentifier positionIDs -PositionIDs -PostInstall -PostMessage -PostUpdate pre prebuild prebuilt precompile preconfigured -Predis prefetch prefixer preload -Preload preloaded prem premapping -Premapping -PreparedPaymentHandlerInterface preprocessor preprocessors preselect -Preselect preselection +prettierrc previewable previewComponent -PreWriteValidationEvent +previewable pricecollectionfacade -PriceCollectionFacade -PriceDefinition -PriceDefinitionField pricefacade -PriceFacade pricefactory -PriceField -PriceFieldSerializer -PrimaryKey -ProductAttributeDataSet -ProductAware -ProductCartProcessor -ProductCartTest -ProductCategoryDefinition -ProductController productCountRoute -ProductCountRouteResponse -ProductDataSelection -ProductDataSet productId -ProductListRoute -ProductManufacturerDefinition -ProductMedia -ProductMediaDefinition productNumber -ProductNumber -ProductOptionRelationDataSet -ProductPage -ProductPriceAttributeDataSet -ProductPriceCalculator -ProductPropertyRelationDataSet productproxy -ProductQuickViewWidget -ProductReviewsWidget -ProductSearchBuilder productsfacade -ProductsFacade -ProductStorer -ProductSubscriber -ProductUpdater -ProductVisibility -ProductWarehouse -ProductWarehouses profiler -Profiler profilers programmatically -PropertyGroupOptionDataSet -Prosemirror -ProseMirror -PRs pseudocode -Pseudocode psh -PSH -PSP -PSR -Punctuations pwa -PWA px py +qa +qa@shopware.com qty's quantityBefore quantityDelta -Quickstart -QuillJS -RabbitMq -RabbitMQ randomHex -RDB +reCAPTCHA readAsArrayBuffer readAsDataURL readAsText -README -Readonly realtime rebranded recalculable -reCAPTCHA -RecipientsAware -RecipientsStorer -RecurringPaymentHandlerInterface -Redict -RedirectResponse redis refactorings referenceField -ReferenceVersion -ReferenceVersionField refundAmount refundId -RefundPaymentHandlerInterface refundPositions refundPrice +RegEx regexes -RegistrationCompletedEvent -RegistrationService reindex -Reindexes reinitializing -ReinstallApps reinstallation -RemoteAddress -RemoteAddressField removeBy renameMedia renderer renderers -Repo repos -repositoryfacade repositoryFactory -RepositoryIterator +repositoryfacade repositorywriterfacade reproducibility requestAdminApi resetUrl -ResetUrlAware -ResetUrlStorer resolvers -RestAPI -RestrictDelete resubmittable rethrown returnUrl revalidation -ReverseInherited -Reviewdog -ReviewFormDataAware -ReviewFormDataStorer rfc roadmap -Roadmap rollbacking -RouteResponse routeScope -RuleConditionService runtime -RuntimeException runtimes -SaaS -SalesAgent -saleschannel salesChannel -SalesChannel salesChannelAware -SalesChannelAware salesChannelContext -SalesChannelContext -SalesChannelContextCreatedEvent -SalesChannelContextResolvedEvent -SalesChannelContextRestoredEvent -SalesChannelContextRestorerOrderCriteriaEvent salesChannelId -SalesChannelId salesChannelLoaded -SalesChannelProductEntity +saleschannel saleschannelrepositoryfacade -SalesChannelRule -Sales Rooms -SameSite sandboxed sarven scalability scalable -ScalarValuesAware -ScalarValuesStorer -ScheduledTask schemas -ScriptEventRegistry scriptResponse scriptresponsefactoryfacade scrollbar scss -SCSS sdk -SDK -SDK's -SDKs -SearchCriteria searchMedia -SearchPage -SearchRanking searchViaAdminApi -SearchWidget secretKey -SecretKey selectable selectbox sellable -Sendfile sendmail seo -SEO -SEOs -SeoUrlRoute -SeoUrlTemplate seperate seperated serializable serializer setFlags setLocaleToEnGb -SetNullOnDelete setProductFixtureVisibility setSalesChannelDomain -settingsItem setToInitialState -SFTP +settingsItem sha -SHA shakable shallowMount shippable -ShippingCountryRule -ShippingMethodPriceCollector -ShippingMethodRoute -ShippingMethodRule -ShippingStreetRule -ShippingZipCodeRule sho -ShopActivatedEvent -ShopDeactivatedEvent -ShopDeletedEvent shopId shopName -ShopNameAware -ShopNameStorer shopUrl shopware -Shopware +shopware's shopwarelabs shopwarepartners -shopware's -Shopware's shorthands -SimpleHttpClient simples simplexml -Sinon -SitemapPage -SKEs skipOnFeature skipTestIfInActive sku slowlog sm smartbar -SMS -SMTP snakeCase -SnippetFileInterface -SomeCoreClassTest -Sonarcube -SonarQube sortings -SPA's -SPAs sql -SQS src srcset -SSHes -SSL stableVersion stackable -Stackhero -StackHero -StackOverflow stacktrace stateId -StateMachineRegistry stateMachineState -StateMachineState -StateMachineStateEntity -StateMachineStateField statesfacade -StatesFacade -StaticEntityRepository statusCode +stdout stemmer stemmers -StockUpdate -StockUpdateFilterProvider -StockUpdater stopwords -Storable -StorableFlow storages -StoreApiResponse -StoreApiRoute storefrontApiRequest -StorefrontController -StorefrontResponse storer -Storer -STP -StringField -StringFields strlen struct -Struct structs stylesheet stylesheets @@ -1465,54 +1622,26 @@ subcontent subdirectories subdirectory subfolder -SubjectAware -SubjectStorer suboptimal subprocessor -Subprocessor subprocessors -SuggestPage supervisord svg -SVG -SVGs sw -SwagAdvDevBundle -SwagB -SwagBasicExample -SwagBasicExampleTheme -SwagDigitalSalesRooms -SwagMigrationBundleExample -SwagMyPlugin -SwagMyPluginSW -swoole swSelect +swoole symfony -Symfony symfony's -Symfony's symlink symlinks -SyncApi -SynchronousPaymentHandlerInterface -Synopsys systemconfigfacade systemd -TaxProvider -TaxProviders -TaxProviderStruct -TCP teardown templated -TemplateDataAware -TemplateDataStorer -TemplateNamespaceHierarchyBuilder templating +testFoo testability -TestCase testenv -testFoo -TestStockUpdateFilter testsuite testsuites textarea @@ -1520,204 +1649,96 @@ th theming themself timeframe -TimeRangeRule tinyint -TinyMCE tipps -TipTap -TipTap's tl -TLS +to's todo tokenized -ToMany tooltip tooltips -Tooltips -ToOne -to's totalAmount tradeoff -transactional -TransactionalAction transactionCapture transactionId -TranslatedField -TranslationDataSet -TranslationsAssociation -TranslationsAssociationField +transactional transpiling -TreeBreadcrumb -TreeBreadcrumbField -TreeLevel -TreeLevelField -TreePath -TreePathField -TreeSelect triggerDeprecated -TriggerReload truthy tsx -TTL -TwigJS typeAndCheck typeAndCheckSearchField -TypeError -TypeError's -typehint -typehinted typeLegacySelectAndCheck typeMultiSelectAndCheck -TypeScript typeSingleSelect typeSingleSelectAndCheck +typehint +typehinted ui -UI -UML un -Unassigning uncomment uncommenting uncompiled und unhandled -UninstallApps uninstallation uniqBy -UnitCollection -UnitEntity -UnitTests unminified -UnoCSS unprefixed unregister -Unregistering unsecure unserialize unstorage unstyled untrusted -Untrusted untyped -UpdateContext -UpdatedAt -UpdatedAtField -UpdatedBy -UpdatedByField updateDestructive -UpdateHtaccess updateViaAdminApi -UpperCamelCase upsert -Upserting url -UrlAware urls -UrlStorer -USD userAware -UserAware -userland userRecovery -UserStorer -Util +userland utils -Utils uuid -Uuid -UUID -UUIDs -UUIDv -UX validator -Validator validators varchar -VARCHAR -VCL -VCS ve -Vercel verifier -versionable -VersionDataPayload -VersionDataPayloadField -VersionField versionId +versionable viewport viewportHeight viewports vimeo -VirtualHosts -Vitepress -Vitest -VM vscode -VSCode vue -Vue -Vuei -VueJs -VueJS -Vue's vuex -Vuex -VueX -WarehouseGroup -WarehouseGroups -WCAG webhook -Webhook webhooks webkit -Webkit -WebKit webpack -Webpack webpackMerge webserver -Webserver -WebSocket wednesday -WeekdayRule -WhitelistRule -WhitelistRuleField whitespace whitespaces wil wishlist -WishlistPage -WishlistWidget -WriteEvents -WriteProtected -WSL www xasjkyld -Xdebug -XDebug xhost's -XHR -XKey xkeys xl -XLIFF xml -XmlHttpRequest -XmlUtils -XorRule xpath -XPath -XQuartz xs xsd -XSS -XVFB yaml -YamlFileLoader yml youtube -YYYY zlib zsh -ZSH zstd diff --git a/Makefile b/Makefile index c1a041378..577943993 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ user := "$(shell id -u):$(shell id -g)" ignored = '/docs/resources/references/* /docs/adr/*' +image = jonasbn/github-action-spellcheck:0.43.0 .PHONY : help lint fix .DEFAULT_GOAL : help @@ -12,7 +13,7 @@ help: ## Show this help @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " \033[32m%-18s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) lint: ## Runs the linting tool - docker run --rm -u ${user} -v "$(shell pwd):/docs:ro" -e INPUT_IGNORE=${ignored} avtodev/markdown-lint:v1.5 \ + docker run --rm -u ${user} -v "$(shell pwd):/docs" -w /docs -e INPUT_IGNORE=${ignored} ${image} \ --config /docs/markdown-style-config.yml /docs fix: ## Runs the linting tool and fixes simple mistakes diff --git a/assets/adr/catalog-import/import-http-schema.yml b/assets/adr/catalog-import/import-http-schema.yml index 4bf2f150c..257fec94d 100644 --- a/assets/adr/catalog-import/import-http-schema.yml +++ b/assets/adr/catalog-import/import-http-schema.yml @@ -1,10 +1,3 @@ - - -::: info -This document represents an architecture decision record (ADR) and has been mirrored from the ADR section in our Shopware 6 repository. -You can find the original version [here](https://github.com/shopware/shopware/blob/trunk/adr/assets/catalog-import/import-http-schema.yml) -::: - openapi: 3.0.3 info: title: Catalog import API diff --git a/assets/adr/content-management/example-cms-aware-admin-menu.png b/assets/adr/content-management/example-cms-aware-admin-menu.png index b39c1de5f..b896bc91d 100644 Binary files a/assets/adr/content-management/example-cms-aware-admin-menu.png and b/assets/adr/content-management/example-cms-aware-admin-menu.png differ diff --git a/assets/adr/message_queue_stats.png b/assets/adr/message_queue_stats.png index 776210661..3a4d5e6c9 100644 Binary files a/assets/adr/message_queue_stats.png and b/assets/adr/message_queue_stats.png differ diff --git a/assets/adr/payment-flow/after-order-payment.svg b/assets/adr/payment-flow/after-order-payment.svg index df0800c21..1ccf66b2f 100644 --- a/assets/adr/payment-flow/after-order-payment.svg +++ b/assets/adr/payment-flow/after-order-payment.svg @@ -1,10 +1,3 @@ - - -::: info -This document represents an architecture decision record (ADR) and has been mirrored from the ADR section in our Shopware 6 repository. -You can find the original version [here](https://github.com/shopware/shopware/blob/trunk/adr/assets/payment-flow/after-order-payment.svg) -::: - G diff --git a/assets/adr/payment-flow/asynchronous-payment.png b/assets/adr/payment-flow/asynchronous-payment.png index cd8bf522e..27543693b 100644 Binary files a/assets/adr/payment-flow/asynchronous-payment.png and b/assets/adr/payment-flow/asynchronous-payment.png differ diff --git a/assets/adr/payment-flow/pre-created-payment.png b/assets/adr/payment-flow/pre-created-payment.png index 6be6fcab3..095215f85 100644 Binary files a/assets/adr/payment-flow/pre-created-payment.png and b/assets/adr/payment-flow/pre-created-payment.png differ diff --git a/assets/adr/payment-flow/synchronous-payment.png b/assets/adr/payment-flow/synchronous-payment.png index a2d59fe9f..cc34d3dc9 100644 Binary files a/assets/adr/payment-flow/synchronous-payment.png and b/assets/adr/payment-flow/synchronous-payment.png differ diff --git a/assets/adr/tideways_benchmark.png b/assets/adr/tideways_benchmark.png index 4a5137c88..1ec3f75ad 100644 Binary files a/assets/adr/tideways_benchmark.png and b/assets/adr/tideways_benchmark.png differ diff --git a/assets/k6-cloud.png b/assets/k6-cloud.png new file mode 100644 index 000000000..caaba4774 Binary files /dev/null and b/assets/k6-cloud.png differ diff --git a/assets/k6-dashboard.png b/assets/k6-dashboard.png new file mode 100644 index 000000000..84e6f438d Binary files /dev/null and b/assets/k6-dashboard.png differ diff --git a/concepts/framework/data-abstraction-layer.md b/concepts/framework/data-abstraction-layer.md index 0019c3c8e..a9a980fd4 100644 --- a/concepts/framework/data-abstraction-layer.md +++ b/concepts/framework/data-abstraction-layer.md @@ -11,7 +11,10 @@ nav: ### Database guide -In contrast to most Symfony applications, Shopware uses no ORM, but a thin abstraction layer called the data abstraction layer \(DAL\). The DAL is implemented with the specific needs of Shopware in mind and lets developers access the database via pre-defined interfaces. Some concepts used by the DAL, like Criteria, may sound familiar to you if you know [Doctrine](https://symfony.com/doc/current/doctrine.html) or other ORMs. A reference to more in-depth documentation about the DAL can be found below. +In contrast to most Symfony applications, Shopware uses no ORM, but a thin abstraction layer called the data abstraction layer \(DAL\). +The DAL is implemented with the specific needs of Shopware in mind and lets developers access the database via pre-defined interfaces. +Some concepts used by the DAL, like Criteria, may sound familiar to you if you know [Doctrine](https://symfony.com/doc/current/doctrine.html) or other ORMs. +A reference to more in-depth documentation about the DAL can be found below. Refer to [Shopware 6.6.5.0 entity relationship model](../../../assets/shopware6-erd.pdf) that depicts different tables and their relationships. @@ -24,11 +27,13 @@ If you want to have it as an image: File → Export → Export as PNG ### CRUD operations -An EntityRepository is used to interact with the DAL. This is the recommended way for developers to interface with the DAL or the database in general. +An EntityRepository is used to interact with the DAL. +This is the recommended way for developers to interface with the DAL or the database in general. ### Provisioning code to use the repositories -Before using the repositories, you will need to get them from the [Dependency Injection Container (DIC)](../../guides/plugins/plugins/plugin-fundamentals/dependency-injection). This is done with [Constructor injection](https://symfony.com/doc/current/service_container/injection_types.html#constructor-injection), so you will need to extend your services constructor by expecting an EntityRepository: +Before using the repositories, you will need to get them from the [Dependency Injection Container (DIC)](../../guides/plugins/plugins/plugin-fundamentals/dependency-injection). +This is done with [Constructor injection](https://symfony.com/doc/current/service_container/injection_types.html#constructor-injection), so you will need to extend your services constructor by expecting an EntityRepository: ```php // /src/Service/DalExampleService.php @@ -55,35 +60,58 @@ You can read more about dependency injection and service registration in Shopwar ### Translations -The DAL was designed, among other things, to enable the special requirements of Shopware's translation system. When a record is read or searched, three language levels are searched. +The DAL was designed, among other things, to enable the special requirements of Shopware's translation system. +When a record is read or searched, three language levels are searched. 1. **Current language**: The first level is the current language that is set and displayed to the user. -1. **Parent language**: the second level is an optional parent language that can be configured. So it is possible to translate certain dialects faster. -1. **System language**: The third and last level is the system language that is selected during the installation. Each entity in the system has a translation in this language. This serves as a final fallback to ensure only one label for the entity in the end. +1. **Parent language**: the second level is an optional parent language that can be configured. +So it is possible to translate certain dialects faster. +1. **System language**: The third and last level is the system language that is selected during the installation. +Each entity in the system has a translation in this language. +This serves as a final fallback to ensure only one label for the entity in the end. -The translations for a record are stored in a separate table. The name of this table is always the same as the table for which the records are translated, with the additional suffix `_translation`. +The translations for a record are stored in a separate table. +The name of this table is always the same as the table for which the records are translated, with the additional suffix `_translation`. ### Versioning -Another feature of the DAL is the versioning it brings with it. This makes it possible to store multiple versions of an entity. All data subordinate to an entity is duplicated and made available under the new version. Multiple entities or changes to different entities can be stored for one version. The versioning was designed for previews, publishing, or campaign features, to prepare changes that are not yet live and to be able to view them in the store. +Another feature that the DAL offers is versioning. +This makes it possible to store multiple versions of a single entity. +All data assigned to an entity is duplicated and made available under the new version. +Multiple entities or changes to different entities can be stored for one version. +The versioning was designed for previews, publishing, or campaign features, to prepare changes that are not yet live and to be able to view them in the store. +Currently, it is not possible (yet) to create a completely new entity with another version than the default live version. +Means, you cannot "draft" the entity first and then update it into the live version. +A live version of your entity is always required, before deriving a new version from it. -The versioning is also reflected in the database. Entities that are versionable always have a compound foreign key: `id`, `version_id`. Also, the foreign keys, which point to a versioned record, always consist of two columns, e.g.: `product_id` and `product_version_id`. +The versioning is also reflected in the database. +Entities that are versionable always have a compound foreign key: `id`, `version_id`. +Also, the foreign keys, which point to a versioned record, always consist of two columns, e.g.: `product_id` and `product_version_id`. ### Context -The context `core/Framework/Context.php` defines important configuration of the shop system and is instantiated once per request. Depending on the passed parameters it can change the CRUD behavior of the DAL. For example when using the currency toggle in the storefront and selecting Dollar instead of Euro, the context currency ID is changed accordingly and all operations now refer to Dollar. +The context `core/Framework/Context.php` defines important configuration of the shop system and is instantiated once per request. +Depending on the passed parameters it can change the CRUD behavior of the DAL. +For example when using the currency toggle in the storefront and selecting Dollar instead of Euro, the context currency ID is changed accordingly and all operations now refer to Dollar. ### Inheritance -Another reason why the DAL was designed is to meet the requirements of the product and variant system. For this purpose, a parent-child inheritance system was implemented in the DAL. This allows variants to inherit records, properties, or even whole associations from the parent or container product. For example, if a variant has not been assigned any categories or images, those of the parent product are used. +Another reason why the DAL was designed is to meet the requirements of the product and variant system. +For this purpose, a parent-child inheritance system was implemented in the DAL. +This allows variants to inherit records, properties, or even whole associations from the parent or container product. +For example, if a variant has not been assigned any categories or images, those of the parent product are used. ### Indexing -The DAL was designed to be optimized for use in ecommerce. One principle has proven to be very effective so far: "The more time you put into indexing data, the faster it is possible to read it". This is reflected in Shopware as follows: +The DAL was designed to be optimized for use in ecommerce. +One principle has proven to be very effective so far: "The more time you put into indexing data, the faster it is possible to read it". +This is reflected in Shopware as follows: * A product is written once every X minutes * A product is called X times every X seconds by a customer. -This varies depending on the store, but the ratio is always the same. Data records are read way more often than they are written. Therefore it is worthwhile to spend a little more time on the writing process in order to minimize the effort required for the reading process. This is done in the DAL via the Entity Indexer pattern. As soon as a product record is written, the corresponding Product Indexer is triggered, which pre-selects certain aggregations and writes them away optimized for the later reading process. - - +This varies depending on the store, but the ratio is always the same. +Data records are read way more often than they are written. +Therefore, it is worthwhile to spend a little more time on the writing process in order to minimize the effort required for the reading process. +This is done in the DAL via the Entity Indexer pattern. +As soon as a product record is written, the corresponding Product Indexer is triggered, which pre-selects certain aggregations and writes them away optimized for the later reading process. diff --git a/guides/hosting/configurations/shopware/environment-variables.md b/guides/hosting/configurations/shopware/environment-variables.md new file mode 100644 index 000000000..04003e2ae --- /dev/null +++ b/guides/hosting/configurations/shopware/environment-variables.md @@ -0,0 +1,40 @@ +--- +nav: + title: Environment Variables + position: 50 + +--- + +# Environment Variables + +This page lists all environment variables that can be used to configure Shopware. + +| Variable | Default Value | Description | +| -------------------------------------- | ----------------------- | ---------------------------------------------------------------------------------------- | +| `APP_ENV` | `prod` | Environment | +| `APP_SECRET` | (empty) | Can be generated with `openssl rand -hex 32` | +| `APP_CACHE_DIR` | `{projectRoot}/var/cache` | Path to a directory to store caches (since 6.6.8.0) | +| `APP_BUILD_DIR` | `{projectRoot}/var/cache` | Path to a temporary directory to create cache folder (since 6.6.8.0) | +| `APP_LOG_DIR` | `{projectRoot}/var/log` | Path to a directory to store logs (since 6.6.8.0) | +| `INSTANCE_ID` | (empty) | Unique Identifier for the Store: Can be generated with `openssl rand -hex 32` | +| `JWT_PRIVATE_KEY` | (empty) | Can be generated with `shopware-cli project generate-jwt --env` | +| `JWT_PUBLIC_KEY` | (empty) | Can be generated with `shopware-cli project generate-jwt --env` | +| `LOCK_DSN` | `flock` | DSN for Symfony locking | +| `APP_URL` | (empty) | Where Shopware will be accessible | +| `BLUE_GREEN_DEPLOYMENT` | `0` | This needs super privilege to create trigger | +| `DATABASE_URL` | (empty) | MySQL credentials as DSN | +| `DATABASE_SSL_CA` | (empty) | Path to SSL CA file | +| `DATABASE_SSL_CERT` | (empty) | Path to SSL Cert file | +| `DATABASE_SSL_KEY` | (empty) | Path to SSL Key file | +| `DATABASE_SSL_DONT_VERIFY_SERVER_CERT` | (empty) | Disables verification of the server certificate (1 disables it) | +| `MAILER_DSN` | `null://localhost` | Mailer DSN (Admin Configuration overwrites this) | +| `OPENSEARCH_URL` | (empty) | Open Search Hosts | +| `SHOPWARE_ES_ENABLED` | `0` | Open Search Support Enabled? | +| `SHOPWARE_ES_INDEXING_ENABLED` | `0` | Open Search Indexing Enabled? | +| `SHOPWARE_ES_INDEX_PREFIX` | (empty) | Open Search Index Prefix | +| `COMPOSER_HOME` | `/tmp/composer` | Caching for the Plugin Manager | +| `SHOPWARE_HTTP_CACHE_ENABLED` | `1` | Is HTTP Cache enabled? | +| `SHOPWARE_HTTP_DEFAULT_TTL` | `7200` | Default TTL for HTTP Cache | +| `MESSENGER_TRANSPORT_DSN` | (empty) | DSN for default async queue (example: `amqp://guest:guest@localhost:5672/%2f/default`) | +| `MESSENGER_TRANSPORT_LOW_PRIORITY_DSN` | (empty) | DSN for low priority queue (example: `amqp://guest:guest@localhost:5672/%2f/low_prio`) | +| `MESSENGER_TRANSPORT_FAILURE_DSN` | (empty) | DSN for failed messages queue (example: `amqp://guest:guest@localhost:5672/%2f/failure`) | diff --git a/guides/hosting/infrastructure/message-queue.md b/guides/hosting/infrastructure/message-queue.md index a784b5be9..bfd588bd5 100644 --- a/guides/hosting/infrastructure/message-queue.md +++ b/guides/hosting/infrastructure/message-queue.md @@ -158,3 +158,78 @@ The number of workers depends on the number of messages queued and the type of m Sometimes, it also makes sense to route messages to a different transport to limit the number of workers for a specific type of message to avoid database locks or prioritize messages like sending emails. + +## Configuration + +### Message bus + +The message bus is used to dispatch your messages to your registered handlers. While dispatching your message, it loops through the configured middleware for that bus. The message bus used inside Shopware can be found under the service tag `messenger.bus.shopware`. It is mandatory to use this message bus if your messages should be handled inside Shopware. However, if you want to send messages to external systems, you can define your custom message bus for that. + +You can configure an array of buses and define one default bus in your `framework.yaml`. + +```yaml +// /src/Core/Framework/Resources/config/packages/framework.yaml +framework: + messenger: + default_bus: messenger.bus.shopware + buses: + messenger.bus.shopware: +``` + +For more information on this check the [Symfony docs](https://symfony.com/doc/current/messenger/multiple_buses.html). + +### Transport + +A [transport](https://symfony.com/doc/current/messenger.html#transports-async-queued-messages) is responsible for communicating with your 3rd party message broker. You can configure multiple transports and route messages to multiple or different transports. Supported are all transports that are either supported by [Symfony](https://symfony.com/doc/current/messenger.html#transport-configuration) itself. If you don't configure a transport, messages will be processed synchronously like in the Symfony event system. + +You can configure an amqp transport directly in your `framework.yaml` and simply tell Symfony to use your transports. + +In a simple setup you only need to set the transport to a valid DSN like: + +```yaml +// /src/Core/Framework/Resources/config/packages/queue.yaml +framework: + messenger: + transports: + my_transport: + dsn: "%env(MESSENGER_TRANSPORT_DSN)%" +``` + +For more information on this check the [symfony docs](https://symfony.com/doc/current/messenger.html#transport-configuration). + +### Routing + +You can route messages to different transports. For that, just configure your routing in the `framework.yaml`. + +```yaml +// /src/ +framework: + messenger: + transports: + async: "%env(MESSENGER_TRANSPORT_DSN)%" + another_transport: "%env(MESSENGER_TRANSPORT_ANOTHER_DSN)%" + routing: + 'Swag\BasicExample\MessageQueue\Message\SmsNotification': another_transport + 'Swag\BasicExample\MessageQueue\Message\AnotherExampleNotification': [async, another_transport] + '*': async +``` + +You can route messages by their classname and use the asterisk as a fallback for all other messages. If you specify a list of transports the messages will be routed to all of them. For more information on this check the [Symfony docs](https://symfony.com/doc/current/messenger.html#routing-messages-to-a-transport). + +#### Routing overwrites + +By default, all messages that implement the `AsyncMessageInterface` will be routed to the `async` transport. The default symfony config detailed above will only let you add additional routing to those messages, however if you need to overwrite the additional routing you can do so by adding the following to your `shopware.yaml`: + +```yaml +shopware: + messenger: + routing_overwrite: + 'Shopware\Core\Framework\DataAbstractionLayer\Indexing\EntityIndexingMessage': entity_indexing +``` + +The `shopware.messenger.routing_overwrite` config option accepts the same format as the `framework.messenger.routing` option, but it will overwrite the routing for the given message class instead of adding to it. +This is especially useful if there is a default routing already configured based on a message interface, but you need to change the routing for a specific message. + +::: info +This configuration option was added in Shopware 6.6.4.0 and 6.5.12.0. +::: diff --git a/guides/hosting/infrastructure/redis.md b/guides/hosting/infrastructure/redis.md index 7deeb82af..e5ff51cad 100644 --- a/guides/hosting/infrastructure/redis.md +++ b/guides/hosting/infrastructure/redis.md @@ -47,6 +47,23 @@ As the data is critical, it is important to use a key eviction policy that will The cart, number range, lock store and increment data is what should be stored in this instance. +## Configuration + +Starting with v6.6.8.0 Shopware supports configuring different reusable Redis connections in the`config/packages/shopware.yaml` file under the `shopware` section: + +```yaml +shopware: + # ... + redis: + connections: + ephemeral: + dsn: 'redis://host1:port/dbindex' + persistent: + dsn: 'redis://host2:port/dbindex?persistent=1' +``` + +Connection names should reflect the actual connection purpose/type and be unique. Also, the names are used as part of the service names in the container, so they should follow the service naming conventions. After defining connections, you can reference them by name in the configuration of different subsystems. + @@ -54,3 +71,5 @@ The cart, number range, lock store and increment data is what should be stored i + + diff --git a/guides/hosting/infrastructure/reverse-http-cache.md b/guides/hosting/infrastructure/reverse-http-cache.md index 6c8dbcb1e..5293df887 100644 --- a/guides/hosting/infrastructure/reverse-http-cache.md +++ b/guides/hosting/infrastructure/reverse-http-cache.md @@ -177,16 +177,18 @@ shopware: ### Fastly VCL Snippets -Additionally, we need to set up some VCL Snippets in the Fastly interface: +You can use the [Deployment Helper to automatically deploy Fastly VCL Snippets and keep them up to date](../installation-updates//deployments/deployment-helper.md). - +For manual deployment, you can find the VCL Snippets here: - + - + - + - + - + + + diff --git a/guides/hosting/installation-updates/cluster-setup.md b/guides/hosting/installation-updates/cluster-setup.md index 6bcc8db62..6a5fbebeb 100644 --- a/guides/hosting/installation-updates/cluster-setup.md +++ b/guides/hosting/installation-updates/cluster-setup.md @@ -43,11 +43,6 @@ The following folders are available in the production template: Most big-scale projects have a development team assigned. It is responsible for the stability and performance of the system. The integration of external sources via apps or plugins can be useful but should always be viewed with a critical eye. By including those sources, the development team relinquishes control over parts of the system. We recommend including necessary plugins as Composer packages instead of user-managed plugins. -## Composer plugin loader - -Shopware loads by default all plugins via the database and allows to enable/disable plugins at runtime. This needs to be fixed in a multi-app server environment. Therefore, we recommend using the Composer plugin loader. The Composer plugin loader loads the plugin state from Composer, so when a plugin is installed using Composer we assume that it is enabled. -That allows you to deploy plugins to all app servers by deploying with installing them using Composer. The plugins must be installed while deployment using `bin/console plugin:install --activate `, so they are ready to use after the deployment. To use the composer plugin loader, add the environment variable `COMPOSER_PLUGIN_LOADER=1` to your `.env` file. - ## Redis We recommend setting up at least five Redis servers for the following resources: diff --git a/guides/hosting/installation-updates/deployments/deployment-helper.md b/guides/hosting/installation-updates/deployments/deployment-helper.md index d4e98a4b5..39f50bfb4 100644 --- a/guides/hosting/installation-updates/deployments/deployment-helper.md +++ b/guides/hosting/installation-updates/deployments/deployment-helper.md @@ -7,10 +7,6 @@ nav: # Deployment Helper -::: warning -The Deployment Helper is experimental and configuration may change in the future. Please use it with caution. -::: - The Deployment Helper is a tool that unifies the steps executed after the Code has been uploaded to the server. On a traditional deployment, you would run it after the files have been uploaded. When using a Containerized environment you would run Deployment Helper with the new source code and then switch over the traffic. @@ -75,8 +71,13 @@ deployment: script: | # runs one time in deployment, then never again ./bin/console --version + + store: + license-domain: 'example.com' ``` +## Environment Variables + Additionally, you can configure the Shopware installation using the following environment variables: - `INSTALL_LOCALE` - The locale to install Shopware with (default: `en-GB`) @@ -84,6 +85,9 @@ Additionally, you can configure the Shopware installation using the following en - `INSTALL_ADMIN_USERNAME` - The username of the admin user (default: `admin`) - `INSTALL_ADMIN_PASSWORD` - The password of the admin user (default: `shopware`) - `SALES_CHANNEL_URL` - The URL of the Storefront sales channel (default: `http://localhost`) +- `SHOPWARE_STORE_ACCOUNT_EMAIL` - The email address of the Shopware account +- `SHOPWARE_STORE_ACCOUNT_PASSWORD` - The password of the Shopware account +- `SHOPWARE_STORE_LICENSE_DOMAIN` - The license domain of the Shopware Shop (default: license-domain value in YAML file) ## One Time Tasks @@ -93,6 +97,27 @@ You can check with `./vendor/bin/shopware-deployment-helper one-time-task:list` To remove a task, use `./vendor/bin/shopware-deployment-helper one-time-task:unmark `. This will cause the task to be executed again during the next update. To manually mark a task as run you can use `./vendor/bin/shopware-deployment-helper one-time-task:mark `. +## Fastly Integration + +The Deployment Helper can also deploy Fastly VCL Snippets for you and keep them up to date. After installing the Deployment Helper, you can install the Fastly meta package: + +```bash +composer require shopware/fastly-meta +``` + +After that, make sure that environment variable `FASTLY_API_KEY` and `FASTLY_SERVICE_ID` are set and the Fastly VCL Snippets will be deployed with the regular deployment process of the Deployment Helper. + +The deployment helper has also two commands to manage the Fastly VCL Snippets: + +- `./vendor/bin/shopware-deployment-helper fastly:snippet:list` - List all VCL snippets that are currently deployed +- `./vendor/bin/shopware-deployment-helper fastly:snippet:remove ` - Remove a VCL snippet by name + +## Automatic Store Login + +The Deployment Helper can automatically log in to the Shopware Store, so you can install Apps from the Store. For this the environment variables: `SHOPWARE_STORE_ACCOUNT_EMAIL` and `SHOPWARE_STORE_ACCOUNT_PASSWORD` need to be set, and a license domain needs to be configured in the `.shopware-project.yml` file. +The license domain can be set also by env variable `SHOPWARE_STORE_LICENSE_DOMAIN`, which will overwrite the value from the `.shopware-project.yml` file. + +When you open the extension manager, you will see that you are not logged in. This is normal as the Deployment Helper does log you in only for system tasks like extension installation or updates. For the extension manager, every Administration user needs to log in manually. ## Usage examples diff --git a/guides/hosting/installation-updates/deployments/deployment-with-deployer.md b/guides/hosting/installation-updates/deployments/deployment-with-deployer.md index 6409c1c49..418ffc4d5 100644 --- a/guides/hosting/installation-updates/deployments/deployment-with-deployer.md +++ b/guides/hosting/installation-updates/deployments/deployment-with-deployer.md @@ -188,7 +188,7 @@ task('sw:health_checks', static function () { }); ``` -> Before incorporating this step into your deployment process, make sure that you are well familiar with the [System Checks Concepts](/concepts/framework/system-check.md) and how to use and interpret the results [Custom usage](/guides/plugins/plugins/framework/system-check/index.md), and the command [error codes](/guides/plugins/plugins/framework/system-check/index.md#triggering-system-checks). +> Before incorporating this step into your deployment process, make sure that you are well familiar with the [System Checks Concepts](../../../../concepts/framework/system-check.md) and how to use and interpret the results [Custom usage](../../../../guides/plugins/plugins/framework/system-check/index.md), and the command [error codes](../../../../guides/plugins/plugins/framework/system-check/index.md#triggering-system-checks). ### 9. Switching the document root diff --git a/guides/hosting/installation-updates/docker.md b/guides/hosting/installation-updates/docker.md new file mode 100644 index 000000000..050b66bc6 --- /dev/null +++ b/guides/hosting/installation-updates/docker.md @@ -0,0 +1,242 @@ +--- +nav: + title: Docker Image + position: 10 + +--- + +Shopware provides a Docker image to run Shopware 6 in a containerized environment for production intent. The Docker image is based on the official PHP image and includes the required PHP extensions and configurations to run Shopware 6. But it does not contain Shopware itself. +It's intended to be used together with your existing Shopware project, copy the project into the image, build it, and run it. + +If you don't have yet a Shopware project, you can create a new one with: + +::: info +You can create a Project with a specific Shopware version by specifying the version like: `composer create-project shopware/production:6.6.7.0 ` +::: + + +```bash +composer create-project shopware/production +cd +composer require shopware/docker +``` + +The typical Dockerfile in your project would look like this: + +```dockerfile +#syntax=docker/dockerfile:1.4 + +ARG PHP_VERSION=8.3 +FROM ghcr.io/shopware/docker-base:$PHP_VERSION-caddy as base-image +FROM ghcr.io/friendsofshopware/shopware-cli:latest-php-$PHP_VERSION as shopware-cli + +FROM shopware-cli as build + +ADD . /src +WORKDIR /src + +RUN --mount=type=secret,id=packages_token,env=SHOPWARE_PACKAGES_TOKEN \ + --mount=type=secret,id=composer_auth,dst=/src/auth.json \ + --mount=type=cache,target=/root/.composer \ + --mount=type=cache,target=/root/.npm \ + /usr/local/bin/entrypoint.sh shopware-cli project ci /src + +FROM base-image + +COPY --from=build --chown=82 --link /src /var/www/html +``` + +The Dockerfile uses the `shopware-cli` image to build the project and then copies the built project into the `base-image` image. The `base-image` is the Shopware Docker image. + +::: info +Instead of copying the Dockerfile to your project, rather run `composer req shopware/docker` to add the Dockerfile to your project. This keeps the Dockerfile up-to-date with the latest changes using Symfony Flex recipes. +::: + +## Available Tags / Versioning + +The Docker image is versioned by the PHP Version and the PHP Patch version. The Docker Image is updated daily and contains the latest security patches. + +The following tags are available with Caddy: + +- `shopware/docker-base:8.3` - PHP 8.3 with Caddy +- `shopware/docker-base:8.3-caddy` - PHP 8.3 with Caddy (same as above, but more explicit) +- `shopware/docker-base:8.3.12-caddy` - PHP 8.3.12 with Caddy (same as above, but much more explicit) +- `shopware/docker-base:8.3-caddy-otel` - PHP 8.3 with Caddy and OpenTelemetry + +We also have Nginx images available: + +- `shopware/docker-base:8.3-nginx` - PHP 8.3 with Nginx (same as above, but more explicit) +- `shopware/docker-base:8.3.12-nginx` - PHP 8.3.12 with Nginx (same as above, but much more explicit) +- `shopware/docker-base:8.3-nginx-otel` - PHP 8.3 with Nginx and OpenTelemetry + +Additionally we have also FPM only images available: + +- `shopware/docker-base:8.3-fpm` - PHP 8.3 with FPM +- `shopware/docker-base:8.3.12-fpm` - PHP 8.3.12 with FPM (same as above, but much more explicit) +- `shopware/docker-base:8.3-fpm-otel` - PHP 8.3 with FPM and OpenTelemetry +- `shopware/docker-base:8.3.12-fpm-otel` - PHP 8.3.12 with FPM and OpenTelemetry (same as above, but much more explicit) + + +The images are available at Docker Hub and GitHub Container Registry (ghcr.io) with the same names and tags. + +## Default installed PHP Extensions + +The Docker image contains the following PHP extensions: `bcmath`, `gd`, `intl`, `mysqli`, `pdo_mysql`, `pcntl`, `sockets`, `bz2`, `gmp`, `soap`, `zip`, `ffi`, `opcache`, `redis`, `apcu`, `amqp` and `zstd` + +## Environment Variables + +| Variable | Default Value | Description | +|--------------------------------------|------------------|------------------------------------------------------------------------------------------| +| `PHP_SESSION_COOKIE_LIFETIME` | 0 | [See PHP FPM documentation](https://www.php.net/manual/en/session.configuration.php) | +| `PHP_SESSION_GC_MAXLIFETIME` | 1440 | [See PHP FPM documentation](https://www.php.net/manual/en/session.configuration.php) | +| `PHP_SESSION_HANDLER` | files | Set to `redis` for redis session | +| `PHP_SESSION_SAVE_PATH` | (empty) | Set to `tcp://redis:6379` for redis session | +| `PHP_MAX_UPLOAD_SIZE` | 128m | See PHP documentation | +| `PHP_MAX_EXECUTION_TIME` | 300 | See PHP documentation | +| `PHP_MEMORY_LIMIT` | 512m | See PHP documentation | +| `PHP_ERROR_REPORTING` | E_ALL | See PHP documentation | +| `PHP_DISPLAY_ERRORS` | 0 | See PHP documentation | +| `PHP_OPCACHE_ENABLE_CLI` | 1 | See PHP documentation | +| `PHP_OPCACHE_FILE_OVERRIDE` | 1 | See PHP documentation | +| `PHP_OPCACHE_VALIDATE_TIMESTAMPS` | 1 | See PHP documentation | +| `PHP_OPCACHE_INTERNED_STRINGS_BUFFER`| 20 | See PHP documentation | +| `PHP_OPCACHE_MAX_ACCELERATED_FILES` | 10000 | See PHP documentation | +| `PHP_OPCACHE_MEMORY_CONSUMPTION` | 128 | See PHP documentation | +| `PHP_OPCACHE_FILE_CACHE` | | See PHP documentation | +| `PHP_OPCACHE_FILE_CACHE_ONLY` | 0 | See PHP documentation | +| `PHP_REALPATH_CACHE_TTL` | 3600 | See PHP documentation | +| `PHP_REALPATH_CACHE_SIZE` | 4096k | See PHP documentation | +| `FPM_PM` | dynamic | [See PHP FPM documentation](https://www.php.net/manual/en/install.fpm.configuration.php) | +| `FPM_PM_MAX_CHILDREN` | 5 | [See PHP FPM documentation](https://www.php.net/manual/en/install.fpm.configuration.php) | +| `FPM_PM_START_SERVERS` | 2 | [See PHP FPM documentation](https://www.php.net/manual/en/install.fpm.configuration.php) | +| `FPM_PM_MIN_SPARE_SERVERS` | 1 | [See PHP FPM documentation](https://www.php.net/manual/en/install.fpm.configuration.php) | +| `FPM_PM_MAX_SPARE_SERVERS` | 3 | [See PHP FPM documentation](https://www.php.net/manual/en/install.fpm.configuration.php) | + +This table contains only the environment variables that are specific to the Shopware Docker image. You can see all Shopware specific environment variables [here](../configurations/shopware/environment-variables.md) + +Additionally, you can use also the [Deployment Helper environment variables](./deployments//deployment-helper.md#environment-variables) to specify default administration credentials, locale, currency, and sales channel URL. + +## Possible Mounts + +::: info +Our recommendation is to store all files in an external storage provider to not mount any volumes. Refer to [official Shopware docs for setup](https://developer.shopware.com/docs/guides/hosting/infrastructure/filesystem). +::: + +In a very basic setup when all files are stored locally you need 5 volumes: + +| Usage | Path | +|------------------------|----------------------------------| +| invoices/private files | `/var/www/html/files` | +| theme files | `/var/www/html/public/theme` | +| images | `/var/www/html/public/media` | +| image thumbnails | `/var/www/html/public/thumbnail` | +| generated sitemap | `/var/www/html/public/sitemap` | + +Shopware logs by default to `var/log`, but when `shopware/docker` Composer package is installed, we change it to stdout. This means you can use `docker logs` to see the logs or use logging driver to forward the logs to a logging service. + +## Ideal Setup + +The ideal setup requires an external storage provider like S3. In that way you don't need any mounts and can scale the instances without any problems. + +Additionally, Redis is required for the session storage and the cache, so the Browser sessions are shared between all instances and cache invalidations are happening on all instances. + +## Typical Setup + +The docker image starts in entry point PHP-FPM / Caddy. So you will need to start a extra container to run maintenance tasks like to install Shopware, install plugins, or run the update. This can be done by installing the [Deployment Helper](./deployments/deployment-helper.md) and creating one container and running as entry point `/setup` + +Here we have an example of a `compose.yaml`, how the services could look like: + +::: info + +This is just an example compose file to demonstrate how the services could look like. It's not a ready to use compose file. You need to adjust it to your needs. + +::: + +```yaml +x-environment: &shopware + image: local + build: + context: . + environment: + DATABASE_URL: 'mysql://shopware:shopware@database/shopware' + APP_URL: 'http://localhost:8000' + volumes: + - files:/var/www/html/files + - theme:/var/www/html/public/theme + - media:/var/www/html/public/media + - thumbnail:/var/www/html/public/thumbnail + - sitemap:/var/www/html/public/sitemap + +services: + database: + image: mariadb:11.4 + + init: + <<: *shopware + entrypoint: /setup + depends_on: + db: + condition: service_started + init-perm: + condition: service_completed_successfully + web: + <<: *shopware + depends_on: + init: + condition: service_completed_successfully + ports: + - 8000:8000 + + worker: + <<: *shopware + depends_on: + init: + condition: service_completed_successfully + entrypoint: [ "php", "bin/console", "messenger:consume", "async", "low_priority", "--time-limit=300", "--memory-limit=512M" ] + deploy: + replicas: 3 + + scheduler: + <<: *shopware + depends_on: + init: + condition: service_completed_successfully + entrypoint: [ "php", "bin/console", "scheduled-task:run" ] +``` + + + +## Best Practices + +- Pin the docker image using a sha256 digest to ensure you always use the same image + - Setup Dependabot / Renovate to keep the image up-to-date +- Use a external storage provider for all files, to keep all state out of the container +- Use Redis/Valkey for Cache and Session storage so all instances share the same cache and session +- Use Nginx Variant instead of Caddy as it's more battle tested + +## Adding custom PHP extensions + +The Docker image is contains the [docker-php-extension-installer](https://github.com/mlocati/docker-php-extension-installer) which allows you to install PHP extensions with the `install-php-extensions` command. + +To install a PHP extension you need to add the following to your Dockerfile: + +```dockerfile +# ... + +RUN install-php-extensions tideways +``` + +## Adding custom PHP configuration + +Create a new INI file at `/usr/local/etc/php/conf.d/` with the extension `.ini` and add your configuration. + +```dockerfile +COPY custom.ini /usr/local/etc/php/conf.d/ +``` + +## FAQ + +### No transport supports the given Messenger DSN for Redis + +When you are stuck with the error `No transport supports the given Messenger DSN`, you need to install the required package. When the package is already installed, it's mostly a dependency resolving issue. Make sure that you have also the PHP Redis Extension locally installed. + diff --git a/guides/hosting/performance/cart-storage.md b/guides/hosting/performance/cart-storage.md index 3ab93edd4..30f428b94 100644 --- a/guides/hosting/performance/cart-storage.md +++ b/guides/hosting/performance/cart-storage.md @@ -16,11 +16,33 @@ Redis is better suited in high-throughput scenarios, therefore you should use Re To use Redis, create a `config/packages/shopware.yml` file with the following content: + + + ```yaml shopware: cart: redis_url: 'redis://host:port/dbindex?persistent=1' ``` + + + + +```yaml +shopware: + redis: + connections: + persistent: + dsn: 'redis://host:port/dbindex?persistent=1' + cart: + storage: + type: 'redis' + config: + connection: 'persistent' +``` + + + It is recommended to use a persistent Redis connection to avoid connection issues in high-load scenarios. ## Migrating between storages diff --git a/guides/hosting/performance/increment.md b/guides/hosting/performance/increment.md index 56b94ddff..d5d8f2cd1 100644 --- a/guides/hosting/performance/increment.md +++ b/guides/hosting/performance/increment.md @@ -20,6 +20,9 @@ Shopware uses the `increment` table to store such information by default. When m To use Redis, create a `config/packages/shopware.yml` file with the following content + + + ```yaml shopware: increment: @@ -33,6 +36,30 @@ shopware: config: url: 'redis://host:port/dbindex' ``` + + + + +```yaml +shopware: + redis: + connections: + persistent: + dsn: 'redis://host:port/dbindex?persistent=1' + + increment: + user_activity: + type: 'redis' + config: + connection: 'persistent' + + message_queue: + type: 'redis' + config: + connection: 'persistent' +``` + + ### Redis configuration @@ -50,8 +77,8 @@ To disable it, create a `config/packages/shopware.yml` file with the following c shopware: increment: user_activity: - type: 'array' + type: 'array' message_queue: - type: 'array' + type: 'array' ``` diff --git a/guides/hosting/performance/k6.md b/guides/hosting/performance/k6.md new file mode 100644 index 000000000..0f6421cc6 --- /dev/null +++ b/guides/hosting/performance/k6.md @@ -0,0 +1,221 @@ +--- +nav: + title: Performance Test with K6 + position: 20 + +--- + +# Testing Shopware Performance with K6 + +K6 is a modern load testing tool that makes it easy to test the performance of your Shopware store. It runs scenario's defined in JavaScript and can be used to simulate hundreds of users accessing your store at the same time, so you can see how your store performs under load. + +## Prerequisites + +Before you start, make sure you have the following prerequisites: + +- A Shopware store +- [K6 installed locally](https://github.com/grafana/k6/releases) +- [Bun](https://bun.sh/) + +## Setting up K6 to run against your Shop + +1. First we need to clone the [Shopware K6 repository](https://github.com/shopware/k6-shopware) and install the dependencies: + +```bash +git clone https://github.com/shopware/k6-shopware.git +cd k6-shopware +bun install +``` + +2. Next copy `.env.example` to `.env` and adjust the values to your Shopware store: + +```bash +cp .env.example .env +``` + +3. After setting up the credentials we need to fetch the fixtures (salutation IDs, country IDs, sales channel configuration): + +```bash +bun run fetch-fixtures.ts +``` + +The K6 test will use the fixtures to find the correct sales channel domain and basic information to create user and orders. + +## Preparations on Shopware end + +Before running the tests on your Shopware store, you need to make sure that the following settings are configured: + +- No captcha is active in login/register form +- Email sending has been disabled (Admin -> Settings -> System -> Mailer -> Disable email sending) + +Also, make sure the Shopware Store has some products and categories, so the test can interact with the store. If you don't have any products, you can use the following command to create some test products: + +```bash +APP_ENV=prod php bin/console framework:demodata +APP_ENV=prod php bin/console dal:refresh:index +``` + +If you need more than the default 1000 products, you can run the command again with: + +```bash +APP_ENV=prod php bin/console framework:demodata --reset-defaults --products=5000 +APP_ENV=prod php bin/console dal:refresh:index +``` + +The command `framework:demodata` can also execute multiple times in parallel, so you can create a lot of products in a short time. Just make sure that you run `dal:refresh:index` after all processes are finished. + +## Running the tests + +To run the tests, we need an scenario file. The repository comes with a example scenario file that you can use to test your store. + +```js +// example.js +import { + accountRegister, + addProductToCart, + placeOrder, + visitCartPage, + visitConfirmPage, + visitNavigationPage, + visitProductDetailPage, + visitSearchPage, + visitStorefront, +} from "./helpers/storefront.js"; + +export default function () { + visitStorefront(); + visitSearchPage(); + visitNavigationPage(); + accountRegister(); + visitNavigationPage(); + addProductToCart(visitProductDetailPage().id); + visitCartPage(); + visitConfirmPage(); + placeOrder(); +} +``` + +So the test does: + +- Visits home page +- Visits a search page with random term +- Visits a random navigation page +- Registers a new account +- Visits a random navigation page +- Visits a product detail page and adds the product to the cart +- Visits the cart page +- Visits the confirm page +- Places an order + +and then the session ends and a new session starts and does it again. + +To run the test, you can use the following command: + +```bash +k6 run example.js +``` + +This will run the test with 1 virtual user and 1 iteration, so you can verify that the test is working correctly. To run the test with more virtual users and iterations, you can use the following command: + +```bash +k6 run --vus 10 --iterations 100 example.js +``` + +so now the test will run with 10 virtual users and 100 iterations. + +## Running multiple scenarios + +You can also run multiple scenarios in the same file. To do this, you can define them in the options like so: + +```js +// example.js +import { productChangePrice, productChangeStocks, fetchBearerToken, useCredentials, productImport } from "./helpers/api.js"; +import { + accountRegister, + addProductToCart, + placeOrder, + visitNavigationPage, + visitProductDetailPage, + visitSearchPage, + visitStorefront, +} from "./helpers/storefront.js"; + +export const options = { + scenarios: { + browse_only: { + executor: 'constant-vus', + vus: 10, + duration: '5m', + exec: 'browseOnly', + }, + fast_buy: { + executor: 'constant-vus', + vus: 1, + duration: '5m', + exec: 'fastBuy', + }, + import: { + executor: 'constant-vus', + vus: 1, + duration: '5m', + exec: 'importer', + } + }, +}; + +export function browseOnly() { + visitStorefront(); + visitSearchPage(); + visitNavigationPage(); + visitProductDetailPage(); +} + +export function fastBuy() { + addProductToCart(visitProductDetailPage().id); + accountRegister(); + placeOrder(); +} + +export function setup() { + const token = fetchBearerToken(); + + return { token }; +} + +export function importer(data) { + useCredentials(data.token); + productImport(); + productChangePrice(); + productChangeStocks(); +} +``` + +and then you can run the test with the following command: + +```bash +k6 run example.js +``` + +This will run the test with 3 scenarios, `browse_only`, `fast_buy` and `import`. When using scenarios, you cannot define the users and iterations anymore in the command-line. They need to be configured in the `options` object in your script. + +There are a lot of options how the scenarios should work together, you can find more information in the [K6 documentation](https://k6.io/docs/using-k6/scenarios/). + +## Enabling the K6 dashboard + +K6 has an embedded dashboard that you can use to monitor the test results in real-time. To enable the dashboard, you can use the following command: + +```bash +K6_WEB_DASHBOARD=true k6 run --vus 10 --duration 5m example.js +``` + +and then you can open http://127.0.0.1:5665/ui/?endpoint=/ in your browser to see the dashboard. + +![K6 Dashboard](../../../assets/k6-dashboard.png) + + +## Running the tests in the Cloud with K6 Cloud + +You can run also the tests in the cloud with K6 Cloud. To do this, you need to create an account on the [K6 Cloud](https://grafana.com/products/cloud/k6/) and get an API token. +This allows you to utilize the K6 Cloud infrastructure to run the tests with a lot of more users, customize the location of the users and get more detailed reports with Grafana Dashboards. + +![K6 Cloud Dashboard](../../../assets/k6-cloud.png) diff --git a/guides/hosting/performance/number-ranges.md b/guides/hosting/performance/number-ranges.md index 88d31558a..c49292f48 100644 --- a/guides/hosting/performance/number-ranges.md +++ b/guides/hosting/performance/number-ranges.md @@ -18,12 +18,32 @@ Redis offers better support for atomic increments than the database. Therefore t To use Redis, create a `config/packages/shopware.yml` file with the following content: + + + +```yaml +shopware: + number_range: + increment_storage: "Redis" + redis_url: 'redis://host:port/dbindex' +``` + + + + ```yaml shopware: - number_range: - increment_storage: "Redis" - redis_url: 'redis://host:port/dbindex' + redis: + connections: + persistent: + dsn: 'redis://host:port/dbindex?persistent=1' + number_range: + increment_storage: 'redis' + config: + connection: 'persistent' ``` + + ### Redis configuration diff --git a/guides/hosting/performance/performance-tweaks.md b/guides/hosting/performance/performance-tweaks.md index 4daede194..315eb17d5 100644 --- a/guides/hosting/performance/performance-tweaks.md +++ b/guides/hosting/performance/performance-tweaks.md @@ -45,7 +45,7 @@ shopware: delay: 1 delay_options: storage: redis - dsn: 'redis://host:port/dbindex' + connection: 'ephemeral' # connection name from redis configuration ``` ## MySQL configuration @@ -92,23 +92,7 @@ If you ever wonder why it is in `prod`, take a look into the [Symfony configurat ## Increment storage The [Increment storage](../performance/increment) is used to store the state and display it in the Administration. -This storage increments or decrements a given key in a transaction-safe way, which causes locks upon the storage. Therefore, we recommend moving this source of server load to a separate Redis: - -```yaml -# config/packages/prod/shopware.yaml -shopware: - increment: - user_activity: - type: 'redis' - config: - url: 'redis://host:port/dbindex' - - message_queue: - type: 'redis' - config: - url: 'redis://host:port/dbindex' -``` - +This storage increments or decrements a given key in a transaction-safe way, which causes locks upon the storage. Therefore, we recommend moving this source of server load to a separate Redis, as described in [Increment storage Redis configuration](./increment#redis-configuration). If you don't need such functionality, it is highly recommended that you disable this behavior by using `array` as a type. ## Lock storage @@ -129,15 +113,7 @@ The generation of the number ranges is an **atomic** operation, which guarantees By default, the number range states are stored in the database. In scenarios where high throughput is required (e.g., thousands of orders per minute), the database can become a performance bottleneck because of the requirement for atomicity. -Redis offers better support for atomic increments than the database. Therefore, the number ranges should be stored in Redis in such scenarios. - -```yaml -# config/packages/prod/shopware.yaml -shopware: - number_range: - increment_storage: "Redis" - redis_url: 'redis://host:port/dbindex' -``` +Redis offers better support for atomic increments than the database. Therefore, the number ranges should be stored in Redis in such scenarios, see [Number Ranges - using Redis as a storage](./number-ranges#using-redis-as-storage). ## Sending mails with the Queue diff --git a/guides/installation/community/dockware.md b/guides/installation/community/dockware.md index 86628930c..69cd5739e 100644 --- a/guides/installation/community/dockware.md +++ b/guides/installation/community/dockware.md @@ -9,7 +9,11 @@ nav: Dockware is basically a managed Docker setup for Shopware 6. It makes it possible to start Shopware 6 very quickly using dockware.io. It comes with everything you need for a smooth development workflow. This includes all available Shopware 6 versions, MySQL, Adminer, Mailcatcher, easy PHP switching, XDebug, useful make commands, and more. +::: info Dockware is maintained by *dasistweb GmbH*. They provide detailed [documentation](https://dockware.io/docs) as well. This way, we will cover just the basics here. +For support please refer to [Dockware GitHub](https://github.com/dockware/dockware). +::: + ## Dockware versions diff --git a/guides/installation/devenv.md b/guides/installation/devenv.md index 84653bac9..3cda7afa3 100644 --- a/guides/installation/devenv.md +++ b/guides/installation/devenv.md @@ -135,14 +135,6 @@ composer require devenv This will create a basic `devenv.nix` file to enable devenv support for Shopware. -Then, leave the temporary shell: - -```shell -exit -``` - -This will remove the php installation that was temporarily created for you inside the nix shell. - diff --git a/guides/installation/requirements.md b/guides/installation/requirements.md index adccf49b1..9f7afa5e2 100644 --- a/guides/installation/requirements.md +++ b/guides/installation/requirements.md @@ -31,24 +31,24 @@ You can use these commands to check your actual environment: * `memory_limit` : 512M minimum * `max_execution_time` : 30 seconds minimum * Extensions: - * ext-curl - * ext-dom - * ext-fileinfo - * ext-gd - * ext-iconv - * ext-intl - * ext-json - * ext-libxml - * ext-mbstring - * ext-openssl (there is an [issue](https://github.com/shopware/shopware/issues/3543) with OpenSSL 3.0.7) - * ext-pcre - * ext-pdo - * ext-pdo\_mysql - * ext-phar - * ext-simplexml - * ext-xml - * ext-zip - * ext-zlib + * `ext-curl` + * `ext-dom` + * `ext-fileinfo` + * `ext-gd` + * `ext-iconv` + * `ext-intl` + * `ext-json` + * `ext-libxml` + * `ext-mbstring` + * `ext-openssl` (there is an [issue](https://github.com/shopware/shopware/issues/3543) with OpenSSL 3.0.7) + * `ext-pcre` + * `ext-pdo` + * `ext-pdo_mysql` + * `ext-phar` + * `ext-simplexml` + * `ext-xml` + * `ext-zip` + * `ext-zlib` * Composer recommended version: 2.0 or higher ### SQL @@ -76,6 +76,7 @@ For optimal MySQL performance, it is advisable to set `max_allowed_packet` to a Shopware uses the Redis Protocol and, therefore, supports the following key/value stores: - [Redis v7 or higher](https://redis.io) +- [Valkey](https://valkey.io/) - [Redict](https://redict.io) - [KeyDB](https://docs.keydb.dev) - [Dragonfly](https://www.dragonflydb.io) @@ -86,153 +87,21 @@ Shopware uses the Redis Protocol and, therefore, supports the following key/valu To run Shopware in a development context, the [Symfony CLI](https://symfony.com/doc/current/setup/symfony_server.html) will work nicely. -Below, you will find the default configuration using either Caddy, Nginx or Apache as a webserver. - - - - -```text -mydomain.com { - header { - X-Frame-Options DENY - Referrer-Policy no-referrer-when-downgrade - } - - @svg { - file - path *.svg - } - - header @svg Content-Security-Policy "script-src 'none'" - - @default { - not path /theme/* /media/* /thumbnail/* /bundles/* /css/* /fonts/* /js/* /recovery/* /sitemap/* - } - - root * public - php_fastcgi 127.0.0.1:9000 - encode zstd gzip - file_server -} -``` - - - - - -```text -server { - listen 80; - - index index.php index.html; - server_name localhost; - - client_max_body_size 32M; - - root __DOCUMENT_ROOT__/public; - - location /recovery/update/ { - index index.php; - try_files $uri /recovery/install/index.php$is_args$args; - } - - location ~ ^/(recovery\/update\/index|index|shopware-installer\.phar)\.php(/|$) { - fastcgi_split_path_info ^(.+\.php)(/.+)$; - include fastcgi.conf; - fastcgi_param HTTP_PROXY ""; - fastcgi_buffers 8 16k; - fastcgi_buffer_size 32k; - proxy_connect_timeout 300s; - proxy_send_timeout 300s; - proxy_read_timeout 300s; - send_timeout 300s; - client_body_buffer_size 128k; - fastcgi_pass unix:/run/php/php8.2-fpm.sock; - } - - location = /sitemap.xml { - log_not_found off; - access_log off; - try_files $uri /; - } - - location = /robots.txt { - log_not_found off; - access_log off; - try_files $uri /; - } - - location ~* ^.+\.(?:css|cur|js|jpe?g|gif|ico|png|svg|webp|avif|html|woff|woff2|xml)$ { - expires 1y; - add_header Cache-Control "public, must-revalidate, proxy-revalidate"; - - access_log off; - - # The directive enables or disables messages in error_log about files not found on disk. - log_not_found off; - - tcp_nodelay off; - - ## Set the OS file cache. - open_file_cache max=3000 inactive=120s; - open_file_cache_valid 45s; - open_file_cache_min_uses 2; - open_file_cache_errors off; - - location ~* ^.+\.svg$ { - add_header Content-Security-Policy "script-src 'none'"; - } - } - - location / { - try_files $uri /index.php$is_args$args; - } -} -``` - - - - - -::: info -The following modules are required: - -* mod_negotiation -* mod_rewrite -* mod_headers -* mod_deflate - -::: - -```text - - ServerName "HOST_NAME" - DocumentRoot _SHOPWARE_LOCATION_/public - - Options -Indexes +FollowSymLinks +MultiViews - AllowOverride All - Order allow,deny - allow from all - - ErrorLog ${APACHE_LOG_DIR}/shopware.error.log - CustomLog ${APACHE_LOG_DIR}/shopware.access.log combined - -``` - - - + + + ## Recommended stack We recommend the following stack: -* Webserver: Caddy -* PHP: 8.2 -* SQL: MySQL 8 or Percona MySQL 8 +* Webserver: Nginx +* PHP: 8.3 +* SQL: MySQL 8.4 or Percona MySQL 8.4 * Node: 20 -* Search: OpenSearch 2.8.0 +* Search: OpenSearch 2.17.1 * Queue: RabbitMQ -* Redis: 7.2 +* Cache: Valkey 8.0 Recommended PHP ini: diff --git a/guides/plugins/apps/app-sdks/javascript/01-getting_started.md b/guides/plugins/apps/app-sdks/javascript/01-getting_started.md index 1cfdd68fc..6ca5306cd 100644 --- a/guides/plugins/apps/app-sdks/javascript/01-getting_started.md +++ b/guides/plugins/apps/app-sdks/javascript/01-getting_started.md @@ -7,14 +7,14 @@ nav: # Getting Started -The app server written in TypeScript and is an open-source project accessible at [app-php-sdk](https://github.com/shopware/app-sdk-js). +The app server written in TypeScript and is an open-source project accessible at [app-sdk-js](https://github.com/shopware/app-sdk-js). ## Installation Install the App PHP SDK via NPM: ```bash -npm install --save @shopware/app-sdk-server +npm install --save @shopware-ag/app-sdk-server ``` After the installation, you can use the SDK in your project. Here is an example: @@ -51,14 +51,19 @@ With this code, you can register your app with our custom app backend. + ```bash bun run index.js ``` + + ```bash deno serve index.js +``` + diff --git a/guides/plugins/apps/app-sdks/javascript/05-http-client.md b/guides/plugins/apps/app-sdks/javascript/05-http-client.md index e020c6eb5..e12e7057d 100644 --- a/guides/plugins/apps/app-sdks/javascript/05-http-client.md +++ b/guides/plugins/apps/app-sdks/javascript/05-http-client.md @@ -110,4 +110,36 @@ await syncService.sync([ The second argument also allows a ApiContext to be passed to configure the API behaviour like disable indexing, or do it using queue asynchronous, disable triggering of flows, etc. +## Abstraction of Media APIs + +The SDK offers helpers to manage the Shopware Media Manager. This allows you to easily upload an media, lookup folders or create new folder. + +```ts +import { createMediaFolder, uploadMediaFile, getMediaFolderByName } from '@shopware-ag/app-server-sdk/helper/media'; + +// The same http client as usual +const httpClient = ...; + +// Create a new folder +const folderId = await createMediaFolder(httpClient, 'My Folder', {}); + +// Create a new folder with parent folder id +const folderId = await createMediaFolder(httpClient, 'My Folder', {parentId: "parent-id"}); + +// Lookup a folder by name +const folderId = await getMediaFolderByName(httpClient, 'My Folder'); + +// Lookup a folder by default folder for an entity +// Returns back the folderId to be used when using a media for a product +const folderId = await getMediaDefaultFolderByEntity(httpClient, 'product'); + +// Upload a file to the media manager +await uploadMediaFile(httpClient, { + file: new Blob(['my text'], { type: 'text/plain' }), + fileName: `foo.text`, + // Optional, a folder id to upload the file to + mediaFolderId: folderId +}); +``` + Next, we will look into the [Integrations](./06-integration). diff --git a/guides/plugins/plugins/administration/add-custom-module.md b/guides/plugins/plugins/administration/add-custom-module.md index e9bd39f63..361646e6c 100644 --- a/guides/plugins/plugins/administration/add-custom-module.md +++ b/guides/plugins/plugins/administration/add-custom-module.md @@ -108,7 +108,7 @@ Shopware.Module.register('swag-example', { title: 'swag-example.general.mainMenuItemGeneral', description: 'sw-property.general.descriptionTextModule', color: '#ff3d58', - icon: 'default-shopping-paper-bag-product', + icon: 'regular-shopping-bag', ... ``` @@ -145,25 +145,8 @@ In this example you would have access to two translations by the following paths You can nest those objects as much as you want. Please note that each path is prefixed by the extension name. Since those translation objects become rather large, you should store them into separate files. -For this purpose, create a new directory `snippet` in your module's directory and in there two new files: `de-DE.json` and `en-GB.json` - -Then, when each file contains your translations as an object, you only have to import them into your module again. - -```javascript -// /src/Resources/app/administration/src/module/swag-example/index.js -[...] - -import deDE from './snippet/de-DE'; -import enGB from './snippet/en-GB'; - -Shopware.Module.register('swag-example', { - ... - snippets: { - 'de-DE': deDE, - 'en-GB': enGB - }, -}); -``` +For this purpose, create a new directory `snippet` in your module's directory and in there two new files: `de-DE.json` and `en-GB.json`. +The snippet files will be loaded automatically based on the folder structure. Let's also create the first translation, which is for your menu's label. It's key should be something like this: `swag-example.general.mainMenuItemGeneral` @@ -235,33 +218,22 @@ import './page/swag-plugin-detail'; Shopware.Module.register('swag-plugin', { ... settingsItem: [{ - group: 'plugin', + group: 'plugins', + icon: 'regular-rocket', to: 'swag.plugin.list', - icon: 'default-object-rocket', - name: 'swag-example.general.mainMenuItemGeneral' + name: 'SwagExampleMenuItemGeneral', // optional, fallback is taken from module + id: '', // optional, fallback is taken from module + label: '', // optional, fallback is taken from module + iconComponent: YourCustomIconRenderingComponent, // optional, this overrides the component used to render the icon }] }); ``` -The `group` property targets to the group section, the item will be displayed in 'shop', 'system' and 'plugins' sections. -The `to` gets the link path of the route. The `icon` contains the icon name which will be display. - -### Add custom settings card +The `group` property determines the tab, the item will be displayed in. Valid options are 'shop', 'system' and 'plugins'. -You can even provide custom setting cards that are either placed in shop, system or plugin tab. -This can be achieved by adding the key settingsItem to your module object: +The `icon` property contains the icon name which will be displayed. Refer to the [Meteor Icon Kit documentation](https://developer.shopware.com/resources/meteor-icon-kit/) for icon names. -```javascript -settingsItem: [{ // this can be a single object if no collection is needed - to: 'custom.module.overview', // route to anything - group: 'system', // either system, shop or plugins - icon: 'default-object-lab-flask', - iconComponent: YourCustomIconRenderingComponent, // optional, this overrides icon attribute - id: '', // optional, fallback is taken from module - name: '', // optional, fallback is taken from module - label: '', // optional, fallback is taken from module -}] -``` +The `to` property must contain the name of the route. The route has to be defined in a separate routes section as described [here](add-custom-route.md). Have a look at the `Configuring the route` section in particular to find out about the name of your route. ## Example for the final module @@ -281,7 +253,7 @@ Shopware.Module.register('swag-example', { title: 'swag-example.general.mainMenuItemGeneral', description: 'sw-property.general.descriptionTextModule', color: '#ff3d58', - icon: 'default-shopping-paper-bag-product', + icon: 'regular-shopping-bag', snippets: { 'de-DE': deDE, @@ -313,7 +285,7 @@ Shopware.Module.register('swag-example', { label: 'swag-example.general.mainMenuItemGeneral', color: '#ff3d58', path: 'swag.example.list', - icon: 'default-shopping-paper-bag-product', + icon: 'regular-shopping-bag', position: 100 }] }); diff --git a/guides/plugins/plugins/administration/add-custom-route.md b/guides/plugins/plugins/administration/add-custom-route.md index 858896d32..3869958a1 100644 --- a/guides/plugins/plugins/administration/add-custom-route.md +++ b/guides/plugins/plugins/administration/add-custom-route.md @@ -34,7 +34,9 @@ routes: { }, ``` -Routes can be matched by name and path. This configuration results in this route's full name being `custom.module.overview` and the URL being `/overview` relative to the Administration's default URL. Usually you want to render your custom component here, which is explained [here](add-custom-component). But that is not all! Routes can have parameters, to then be handed to the components being rendered and much more. Learn more about what the Vue Router can do in its official [Documentation](https://router.vuejs.org/guide/essentials/dynamic-matching.html#reacting-to-params-changes). +Routes can be matched by name and path. This configuration results in this route's full name being `custom.module.overview` and the URL being `/custom/module/overview` relative to the Administration's default URL. The routes full name is a combination of the module's id and the name of the item inside the `routes` object. In this case the module's id is `custom-module` (Notice that all dashes are automatically replaced by dots in the final route name). + +Usually you want to render your custom component here, which is explained [here](add-custom-component). But that is not all! Routes can have parameters, to then be handed to the components being rendered and much more. Learn more about what the Vue Router can do in its official [Documentation](https://router.vuejs.org/guide/essentials/dynamic-matching.html#reacting-to-params-changes). ## Meta data and dynamic parameters diff --git a/guides/plugins/plugins/administration/writing-templates.md b/guides/plugins/plugins/administration/writing-templates.md index 084b90623..057731ec2 100644 --- a/guides/plugins/plugins/administration/writing-templates.md +++ b/guides/plugins/plugins/administration/writing-templates.md @@ -62,4 +62,4 @@ Vue is used to link the data and the DOM in order to make them reactive. Learn a ## More interesting topics * [Add custom styling](add-custom-styles) -* [Adding shortcuts](https://github.com/shopware/docs/tree/575c2fa12ef272dc25744975e2f1e4d44721f0f1/guides/plugins/plugins/administration/add-shortcuts.md) +* [Adding shortcuts](./add-shortcuts.md) diff --git a/guides/plugins/plugins/checkout/document/add-custom-document.md b/guides/plugins/plugins/checkout/document/add-custom-document.md index 2b2939fed..568bf3d14 100644 --- a/guides/plugins/plugins/checkout/document/add-custom-document.md +++ b/guides/plugins/plugins/checkout/document/add-custom-document.md @@ -120,7 +120,7 @@ SQL; WHERE type_id = :typeId SQL; $salesChannelId = $connection->fetchOne($sql, [ - ':typeId' => Uuid::fromHexToBytes(Defaults::SALES_CHANNEL_TYPE_STOREFRONT) + 'typeId' => Uuid::fromHexToBytes(Defaults::SALES_CHANNEL_TYPE_STOREFRONT) ]); if (!$salesChannelId) { diff --git a/guides/plugins/plugins/framework/data-handling/entities-via-attributes.md b/guides/plugins/plugins/framework/data-handling/entities-via-attributes.md index d4eca937f..8c0b8dbcc 100644 --- a/guides/plugins/plugins/framework/data-handling/entities-via-attributes.md +++ b/guides/plugins/plugins/framework/data-handling/entities-via-attributes.md @@ -7,23 +7,31 @@ nav: # Entities via attributes -Since Shopware v6.6.3.0, it has been possible to register entities via PHP attributes. This guide will demonstrate the process. +Since Shopware v6.6.3.0, it has been possible to register entities via PHP attributes. +This guide will demonstrate the process. ## Define the entity -First, you need to define your entity. This is done by creating a new class extending `Entity` and adding the `Entity` attribute to it. The `name` parameter denotes the name of the entity. It is required and must be unique. +First, you need to define your entity. +This is done by creating a new class extending `Entity` and adding the `Entity` attribute to it. +The `name` parameter denotes the name of the entity. It is required and must be unique. -You have to define a primary key. The primary key is defined by adding the `PrimaryKey` attribute to a property. In theory, the primary key can be of any type, but it is recommended to use a `UUID`. +You can also supply the entity collection class to use for this entity, by specifying the `collectionClass` parameter. +The default `EntityCollection` class is used if none is specified. +Note: this is only possible since 6.6.9.0 + +You have to define a primary key. The primary key is defined by adding the `PrimaryKey` attribute to a property. +In theory, the primary key can be of any type, but it is recommended to use a `UUID`. ```php - @@ -44,13 +55,26 @@ To register the entity, you have to add this class to the DI container in the `s ``` -That's it. Your entity is registered and you can read and write data to it over the DAL. Using the tag, Shopware automatically registers an `EntityDefinition` and `EntityRepository` for the entity. +That's it. +Your entity is registered, and you can read and write data to it over the DAL. +Using the tag, Shopware automatically registers an `EntityDefinition` and `EntityRepository` for the entity. ## Field Types -To define more fields, you typically use the `Field` attribute. The `Field` attribute requires the `type` parameter, which is the type of the field. The type can be any of the `FieldType` constants. +To define more fields, you typically use the `Field` attribute. +The `Field` attribute requires the `type` parameter, which is the type of the field. +The type can be any of the `FieldType` constants. ```php +|null */ @@ -415,6 +586,12 @@ class ExampleEntity extends Entity #[ManyToMany(entity: 'currency', onDelete: OnDelete::CASCADE)] public ?array $currencies = null; + /** + * @var array + */ + #[ManyToMany(entity: 'order', onDelete: OnDelete::CASCADE)] + public ?array $orders = null; + /** * @var array|null */ @@ -422,4 +599,21 @@ class ExampleEntity extends Entity public ?array $translations = null; } -``` \ No newline at end of file + + + */ +class ExampleEntityCollection extends EntityCollection +{ + protected function getExpectedClass(): string + { + return ExampleEntity::class; + } +} +``` diff --git a/guides/plugins/plugins/framework/data-handling/versioning-entities.md b/guides/plugins/plugins/framework/data-handling/versioning-entities.md index 4f17ecf2b..9407ef389 100644 --- a/guides/plugins/plugins/framework/data-handling/versioning-entities.md +++ b/guides/plugins/plugins/framework/data-handling/versioning-entities.md @@ -9,13 +9,16 @@ nav: ## Overview -In this guide you will learn how to version your entities. The entity versioning system in Shopware gives you the opportunity to create multiple versions of an entity, which could be used to save drafts for example. +In this guide you will learn how to version your entities. +The entity versioning system in Shopware gives you the opportunity to create multiple versions of an entity, which could be used to save drafts for example. +Learn more about the versioning concept [here](../../../../../concepts/framework/data-abstraction-layer#versioning). ## Prerequisites -In order to add your own versioned entities for your plugin, you first need a plugin as base. Therefore, you can refer to the [Plugin Base Guide](../../plugin-base-guide). +In order to add your own versioned entities for your plugin, you first need a plugin as base. +Therefore, you can refer to the [Plugin Base Guide](../../plugin-base-guide). -Furthermore you should have a look at our [Adding custom complex data](add-custom-complex-data) guide, since this guide is built upon it. +Furthermore, you should have a look at our [Adding custom complex data](add-custom-complex-data) guide, since this guide is built upon it. ## Adjust migration @@ -32,7 +35,8 @@ ALTER TABLE `swag_example` ## Adjust definition -After we've added the new field to our table, we also have to add it to our definition. For this we use a `Shopware\Core\Framework\DataAbstractionLayer\Field\VersionField` which is always required, if we want to version our entity. +After we've added the new field to our table, we also have to add it to our definition. +For this we use a `Shopware\Core\Framework\DataAbstractionLayer\Field\VersionField` which is always required, if we want to version our entity. ```php // /src/Core/Content/Example/ExampleDefinition.php @@ -47,7 +51,9 @@ protected function defineFields(): FieldCollection ## Create and merge version -In this section we will create a new version of our entity which will create a new entry in the database with our updated values. When we merge a particular version, all versions before the merged version are deleted. In the example below, we are using a service where we injected a `swag_example.repository`. +In this section we will create a new version of our entity which will create a new entry in the database with our updated values. +When we merge a particular version, all versions before the merged version are deleted. +In the example below, we are using a service where we injected a `swag_example.repository`. ```php // /src/ @@ -91,21 +97,31 @@ public function exampleVersioning(Context $context): void As you can see above, we first created a new `ExampleEntity` with the description 'This is an example'. -Then we created a new version of our entity with the appropriate repository method `createVersion` and as arguments the id of our created entity and the context. This method returns the id of our new entity version, which we have stored in a variable. +Then we created a new version of our entity with the appropriate repository method `createVersion` and as arguments the id of our created entity and the context. +This method returns the id of our new entity version, which we have stored in a variable. -Next, we used the `createWithVersionId` method of our `Context` to create a new context with our new versionId assigned to it. This new `Context` is used to update the `ExampleEntity`. In our case we have updated the description to 'This is our new description'. By using the updated context with the new `versionId`, the DAL knows that we want to update this version of our entity. +Next, we used the `createWithVersionId` method of our `Context` to create a new context with our new versionId assigned to it. +This new `Context` is used to update the `ExampleEntity`. +In our case we have updated the description to 'This is our new description'. +By using the updated context with the new `versionId`, the DAL knows that we want to update this version of our entity. -Subsequently, we searched the repository with the original context and our new versioned context. In the first search result, using the original context, we get the first version of our entity, which we created at the beginning. With the second search result we get the updated entity, using our new versioned context. +Subsequently, we searched the repository with the original context and our new versioned context. +In the first search result, using the original context, we get the first version of our entity, which we created at the beginning. +With the second search result we get the updated entity, using our new versioned context. -Lastly, we used the repository method `merge` with our versionId, which deletes all versions before this one. The merged version is now our new live version. From now on we can find it without using a versioned context. +Lastly, we used the repository method `merge` with our versionId, which deletes all versions before this one. +The merged version is now our new live version. From now on we can find it without using a versioned context. ## Versioning with foreign keys -If you have an entity with foreign keys, your foreign keys also need to be versioned. In this example we're using an inherited field. If you are not familiar with inheritance, head over to our [Field inheritance](field-inheritance) guide. +If you have an entity with foreign keys, your foreign keys also need to be versioned. +In this example we're using an inherited field. +If you are not familiar with inheritance, head over to our [Field inheritance](field-inheritance) guide. ### Migration -In this step we have to additionally add a foreign key constraint for your `parent_id` and `parent_version_id` referencing to our `id` and `version_id`. The same pattern applies to other entities. +In this step we have to additionally add a foreign key constraint for your `parent_id` and `parent_version_id` referencing to our `id` and `version_id`. +The same pattern applies to other entities. ```sql ALTER TABLE `swag_example` @@ -119,7 +135,8 @@ ALTER TABLE `swag_example` ### Definition -After we've added the new field to our table, we also have to add it to our definition. For this we use a `Shopware\Core\Framework\DataAbstractionLayer\Field\ReferenceVersionField` which references to our entity by using `self::class` and the related field `parent_version_id`. +After we've added the new field to our table, we also have to add it to our definition. +For this we use a `Shopware\Core\Framework\DataAbstractionLayer\Field\ReferenceVersionField` which references to our entity by using `self::class` and the related field `parent_version_id`. ```php // /src/Core/Content/Example/ExampleDefinition.php diff --git a/guides/plugins/plugins/framework/message-queue/add-message-handler.md b/guides/plugins/plugins/framework/message-queue/add-message-handler.md index 70ab096e5..23f718603 100644 --- a/guides/plugins/plugins/framework/message-queue/add-message-handler.md +++ b/guides/plugins/plugins/framework/message-queue/add-message-handler.md @@ -44,152 +44,9 @@ class SmsHandler } ``` -## Consuming messages - -There is a console command to start a worker that will receive incoming messages from your transport and dispatch them. Simply start the worker with the following command: - -```bash -// -bin/console messenger:consume async -``` - -You can also append more transports to the command, so the worker will consume messages from multiple transports which will result in prioritization as mentioned in [Prioritized Transports](https://symfony.com/doc/current/messenger.html#prioritized-transports): - -```bash -// -bin/console messenger:consume async low_priority -``` - -Where `async` and `low_priority` are the transports you want to consume messages from. There is also an API route that lets you consume messages for a given transport. send a `POST` request to the route `/api/_action/message-queue/consume` and define the transport which you want to consume: - -```js -// on -{ - "receiver": "async" -} -``` - -The receiver will consume messages for 2 seconds and then you get the count of the handled messages in the response: - -```js -// on -{ - "handledMessages": 15 -} -``` - -### The admin-worker - -Per default there is an admin-worker that will periodically ping the endpoint to consume messages from the Administration. This feature is intended for development and hosting environments where a more complex setup is not feasible. However, you really should use the cli-worker in production setups, because the admin-worker just consumes messages if an Administration user is logged in. - -### The cli-worker - -The recommended way to consume messages is through the cli command. You can configure the command to run a certain amount of time or to stop if it exceeds a certain memory limit like: - -```bash -// -bin/console messenger:consume async low_priority --time-limit=60 -``` - -```bash -// -bin/console messenger:consume async low_priority --memory-limit=128M -``` - -For more information about the command and its configuration use the `-h` option: - -```bash -// -bin/console messenger:consume -h -``` - -You should use the limit option to periodically restart the worker processes, because of the memory leak issues of long running php processes. To automatically start the processes again after they stopped because of exceeding the given limits you can use something like [upstart](http://upstart.ubuntu.com/getting-started.html) or [supervisor](http://supervisord.org/running.html). Alternatively you can configure a `CronJob` that runs the command periodically. - -If you have configured the cli-worker, you can turn off the admin worker in your `shopware.yaml`. - -```yaml -// /src/Core/Framework/Resources/config/packages/shopware.yaml -shopware: - admin_worker: - enable_admin_worker: false -``` - -**Note:** This will disable the AdminWorker completely and you have to configure the cli-worker for scheduled tasks as well. - -## Configuration - -### Message bus - -The message bus is used to dispatch your messages to your registered handlers. While dispatching your message it loops through the configured middleware for that bus. The message bus used inside Shopware can be found under the service tag `messenger.bus.shopware`. It is mandatory to use this message bus if your messages should be handled inside Shopware. However if you want to send messages to external systems you can define your custom message bus for that. - -You can configure an array of buses and define one default bus in your `framework.yaml`. - -```yaml -// /src/Core/Framework/Resources/config/packages/framework.yaml -framework: - messenger: - default_bus: messenger.bus.shopware - buses: - messenger.bus.shopware: -``` - -For more information on this check the [Symfony docs](https://symfony.com/doc/current/messenger/multiple_buses.html). - -### Transport - -A [transport](https://symfony.com/doc/current/messenger.html#transports-async-queued-messages) is responsible for communicating with your 3rd party message broker. You can configure multiple transports and route messages to multiple or different transports. Supported are all transports that are either supported by [Symfony](https://symfony.com/doc/current/messenger.html#transport-configuration) itself. If you don't configure a transport, messages will be processed synchronously like in the Symfony event system. - -You can configure an amqp transport directly in your `framework.yaml` and simply tell Symfony to use your transports. - -In a simple setup you only need to set the transport to a valid DSN like: - -```yaml -// /src/Core/Framework/Resources/config/packages/queue.yaml -framework: - messenger: - transports: - my_transport: - dsn: "%env(MESSENGER_TRANSPORT_DSN)%" -``` - -For more information on this check the [symfony docs](https://symfony.com/doc/current/messenger.html#transport-configuration). - -### Routing - -You can route messages to different transports. For that, just configure your routing in the `framework.yaml`. - -```yaml -// /src/ -framework: - messenger: - transports: - async: "%env(MESSENGER_TRANSPORT_DSN)%" - another_transport: "%env(MESSENGER_TRANSPORT_ANOTHER_DSN)%" - routing: - 'Swag\BasicExample\MessageQueue\Message\SmsNotification': another_transport - 'Swag\BasicExample\MessageQueue\Message\AnotherExampleNotification': [async, another_transport] - '*': async -``` - -You can route messages by their classname and use the asterisk as a fallback for all other messages. If you specify a list of transports the messages will be routed to all of them. For more information on this check the [Symfony docs](https://symfony.com/doc/current/messenger.html#routing-messages-to-a-transport). - -### Admin worker - -::: warning -The `transports` option can only be configured with the `low_priority` transport if you are on version 6.5.7.0 or above. You must not add the `low_priority` transport in lower versions, as the admin worker will fail when it tries to consume a non-existent transport. -::: - -The admin-worker can be configured or disabled in the general `shopware.yml` configuration. If you want to use the admin worker you have to specify each transport, that previously was configured. The poll interval is the time in seconds that the admin-worker polls messages from the queue. After the poll-interval is over the request terminates and the Administration initiates a new request. +## Next steps -```yaml -// /src/Core/Framework/Resources/config/packages/shopware.yaml -shopware: - admin_worker: - enable_admin_worker: true - poll_interval: 30 - transports: ["async", "low_priority"] -``` +Now that you know how to add a message handler, you may want to add a custom middleware for your bus. To do this, head over to [Add middleware](add-middleware) guide. -## Next steps +If you want to learn more about configuring the message queue, have a look at the [Message queue hosting guide](../../../../hosting/infrastructure/message-queue.md). -Now that you know how to add a message handler and configure a bus for it, you may want to add a custom middleware for your bus. To do this, head over to [Add middleware](add-middleware) guide. diff --git a/guides/plugins/plugins/framework/message-queue/add-message-to-queue.md b/guides/plugins/plugins/framework/message-queue/add-message-to-queue.md index 98a7eff72..2eda82317 100644 --- a/guides/plugins/plugins/framework/message-queue/add-message-to-queue.md +++ b/guides/plugins/plugins/framework/message-queue/add-message-to-queue.md @@ -103,8 +103,8 @@ public function sendMessage(string $message): void You might consider using the new `low_priority` queue if you are dispatching messages that do not need to be handled immediately. To configure specific messages to be transported via the `low_priority` queue, you need to either adjust the routing or implement the `LowPriorityMessageInterface` as already mentioned: ```yaml -# config/packages/framework.yaml -framework: +# config/packages/shopware.yaml +shopware: messenger: routing_overwrite: 'Your\Custom\Message': low_priority @@ -129,8 +129,8 @@ class LowPriorityMessage implements LowPriorityMessageInterface ``` ```yaml -# config/packages/framework.yaml -framework: +# config/packages/shopware.yaml +shopware: messenger: routing_overwrite: 'Shopware\Core\Framework\MessageQueue\LowPriorityMessageInterface': low_priority diff --git a/guides/plugins/plugins/plugin-base-guide.md b/guides/plugins/plugins/plugin-base-guide.md index 0258c47da..5425f0523 100644 --- a/guides/plugins/plugins/plugin-base-guide.md +++ b/guides/plugins/plugins/plugin-base-guide.md @@ -110,7 +110,7 @@ Here's an example `composer.json` for this guide, which will do the trick: } ], "require": { - "shopware/core": "6.5.*" + "shopware/core": "~6.6.0" }, "extra": { "shopware-plugin-class": "Swag\\BasicExample\\SwagBasicExample", diff --git a/guides/plugins/plugins/plugin-fundamentals/add-plugin-configuration.md b/guides/plugins/plugins/plugin-fundamentals/add-plugin-configuration.md index bfdd976c4..6a62a7b0a 100644 --- a/guides/plugins/plugins/plugin-fundamentals/add-plugin-configuration.md +++ b/guides/plugins/plugins/plugin-fundamentals/add-plugin-configuration.md @@ -11,7 +11,8 @@ The `Shopware plugin system` provides you with the option to create a configurat ## Prerequisites -To build your own configuration page for your plugin, you first need a plugin as base. Therefore, you can refer to the [Plugin Base Guide](../plugin-base-guide). +To build your own configuration page for your plugin, you first need a plugin as base. +Therefore, you can refer to the [Plugin Base Guide](../plugin-base-guide). ## Create your plugin configuration @@ -21,7 +22,9 @@ To build your own configuration page for your plugin, you first need a plugin as This video is part of the online training ["Backend Development"](https://academy.shopware.com/courses/shopware-6-backend-development-with-jisse-reitsma) available on Shopware Academy for **free**. ::: -All you need to do is creating a `config.xml` file inside of a `Resources/config` directory in your plugin root. The content of the `config.xml` will be dynamically rendered in the Administration. Below you'll find an example structure: +All you need to do is create a `config.xml` file inside a `Resources/config` directory in your plugin root. +The content of the `config.xml` will be dynamically rendered in the Administration. +Below you'll find an example structure: ```text └── plugins @@ -40,10 +43,13 @@ As you now know how to create configurations, you can start to fill it with life ### Cards in your configuration -The `config.xml` follows a simple syntax. You can organize the content in `` elements. Every `config.xml` must contain a minimum of one `` element and each `` must contain one `` and at least one ``. See the minimum `config.xml` below: +The `config.xml` follows a simple syntax. +You can organize the content in `` elements. +Every `config.xml` must contain a minimum of one `` element and each `` must contain one `` and at least one `<input-field>`. +See the minimum `config.xml` below: ```xml -// <plugin root>/src/Resources/config/config.xml +<!--<plugin root>/src/Resources/config/config.xml--> <?xml version="1.0" encoding="UTF-8"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/shopware/shopware/trunk/src/Core/System/SystemConfig/Schema/config.xsd"> @@ -56,11 +62,13 @@ The `config.xml` follows a simple syntax. You can organize the content in `<card </config> ``` -Please make sure to specify the `xsi:noNamespaceSchemaLocation` as shown above and fetch the external resource into your IDE if possible. This enables auto-completion and suggestions for this XML file and will therefore help you to prevent issues and bugs. +Please make sure to specify the `xsi:noNamespaceSchemaLocation` as shown above and fetch the external resource into your IDE if possible. +This enables auto-completion and suggestions for this XML file and will therefore help you to prevent issues and bugs. ### Card Titles -A `<card>` `<title>` is translatable, this is managed via the `lang` attribute. By default, the `lang` attribute is set to `en-GB`, to change the locale of a `<title>` just add the attribute as follows: +A `<card>` `<title>` is translatable, this is managed via the `lang` attribute. +By default, the `lang` attribute is set to `en-GB`, to change the locale of a `<title>` just add the attribute as follows: ```html ... @@ -73,41 +81,58 @@ A `<card>` `<title>` is translatable, this is managed via the `lang` attribute. ### Input fields -As you can see above, every `<input-field>` has to contain at least a `<name>` element. The `<name>` element is not translatable and has to be unique, since it will be used as the technical identifier for the config element. The field `<name>` must at least be 4 characters long and consist of only lower and upper case letters. It can contain numbers, but not at first place - see this pattern: `[a-zA-Z][a-zA-Z0-9]*` +As you can see above, every `<input-field>` has to contain at least a `<name>` element. +The `<name>` element is not translatable and has to be unique, since it will be used as the technical identifier for the config element. +The field `<name>` must at least be 4 characters long and consist of only lower and upper case letters. +It can contain numbers, but not at first place - see this RegEx pattern: `[a-zA-Z][a-zA-Z0-9]*` ### The different types of input field -Your `<input-field>` can be of different types, this is managed via the `type` attribute. Unless defined otherwise, your `<input-field>` will be a text field per default. Below you'll find a list of all available `<input-field type="?">`. - -| Type | Configuration settings | Renders | Default value example -| :--- | :--- | :--- | :--- | -| text | [copyable](add-plugin-configuration#copyable), [placeholder](add-plugin-configuration#label-placeholder-and-help-text) | Text field | Some text -| textarea | [copyable](add-plugin-configuration#copyable), [placeholder](add-plugin-configuration#label-placeholder-and-help-text) | Text area | Some more text -| text-editor | [placeholder](add-plugin-configuration#label-placeholder-and-help-text) | HTML editor | Some text with HTML `<div>`tags`</div>` -| url | [copyable](add-plugin-configuration#copyable), [placeholder](add-plugin-configuration#label-placeholder-and-help-text) | URL field | https://example.com -| password | [placeholder](add-plugin-configuration#label-placeholder-and-help-text) | Password field | ******** -| int | | Integer field | 42 -| float | | Float field | 42.42 -| bool | | Switch | `true` or `false` -| checkbox | | Checkbox | `true` or `false` -| datetime | | Date-time picker | 2024-04-04T12:00:00.000Z -| date | | Date picker | 2024-04-05T00:00:00 -| time | | Time picker | 11:00:00 -| colorpicker | | Color picker | #189EFF -| single-select | [options](add-plugin-configuration#options), [placeholder](add-plugin-configuration#label-placeholder-and-help-text) | Single-Select box | option_id -| multi-select | [options](add-plugin-configuration#options), [placeholder](add-plugin-configuration#label-placeholder-and-help-text) | Multi-Select box | [option_id1, option_id2] +Your `<input-field>` can be of different types, this is managed via the `type` attribute. +Unless defined otherwise, your `<input-field>` will be a text field. +Below you'll find a list of all available `<input-field type="?">`. + +| Type | Configuration settings | Renders | Default value example | +|:--------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------------|:----------------------------------------| +| text | [copyable](add-plugin-configuration#copyable), [placeholder](add-plugin-configuration#label-placeholder-and-help-text), [length](add-plugin-configuration#text-length-restrictions) | Text field | Some text | +| textarea | [copyable](add-plugin-configuration#copyable), [placeholder](add-plugin-configuration#label-placeholder-and-help-text) | Text area | Some more text | +| text-editor | [placeholder](add-plugin-configuration#label-placeholder-and-help-text) | HTML editor | Some text with HTML `<div>`tags`</div>` | +| url | [copyable](add-plugin-configuration#copyable), [placeholder](add-plugin-configuration#label-placeholder-and-help-text), [length](add-plugin-configuration#text-length-restrictions) | URL field | https://example.com | +| password | [placeholder](add-plugin-configuration#label-placeholder-and-help-text), [length](add-plugin-configuration#text-length-restrictions) | Password field | ******** | +| int | [length](add-plugin-configuration#number-length-restrictions) | Number field | 42 | +| float | [length](add-plugin-configuration#number-length-restrictions) | Number field | 42.42 | +| bool | | Switch | `true` or `false` | +| checkbox | | Checkbox | `true` or `false` | +| datetime | | Date-time picker | 2024-04-04T12:00:00.000Z | +| date | | Date picker | 2024-04-05T00:00:00 | +| time | | Time picker | 11:00:00 | +| colorpicker | | Color picker | #189EFF | +| single-select | [options](add-plugin-configuration#options), [placeholder](add-plugin-configuration#label-placeholder-and-help-text) | Single-Select box | option_id | +| multi-select | [options](add-plugin-configuration#options), [placeholder](add-plugin-configuration#label-placeholder-and-help-text) | Multi-Select box | [option_id1, option_id2] | ### Input field settings -These settings are used to configure your `<input-field>`. **Every `<input-field>` has to start with the `<name>` element.** After the `<name>` element you can configure any of the other settings mentioned above. Beside these settings, they have the following in common: [label](add-plugin-configuration#label-placeholder-and-help-text), [helpText](add-plugin-configuration#label-placeholder-and-help-text), [defaultValue](add-plugin-configuration#defaultvalue) and [disabled](add-plugin-configuration#disabled). +These settings are used to configure your `<input-field>`. +**Every `<input-field>` has to start with the `<name>` element.** +After the `<name>` element you can configure any of the other settings mentioned above. +Beside these settings, they have the following in common: +[label](add-plugin-configuration#label-placeholder-and-help-text), +[helpText](add-plugin-configuration#label-placeholder-and-help-text), +[defaultValue](add-plugin-configuration#defaultvalue), +[disabled](add-plugin-configuration#disabled), +and [required](add-plugin-configuration#required). #### Label, placeholder and help text -The settings `<label>`, `<placeholder>` and `<helpText>` are used to label and explain your `<input-field>` and are translatable. You define your `<label>`, `<placeholder>` and `<helpText>` the same way as the `<card><title>`, with the `lang` attribute. Please remember, that the `lang` attribute is set to `en-GB` per default. +The settings `<label>`, `<placeholder>` and `<helpText>` are used to label and explain your `<input-field>` and are translatable. +You define your `<label>`, `<placeholder>` and `<helpText>` the same way as the `<card><title>`, with the `lang` attribute. +Please remember, that the `lang` attribute is set to `en-GB` per default. #### defaultValue -Add the `defaultValue` setting to your `<input-field>` to define a default value for it. This value will be imported into the database on installing and updating the plugin. We use [Symfony\Component\Config\Util\XmlUtils](https://github.com/symfony/config/blob/master/Util/XmlUtils.php#L215) for casting the values into the correct PHP types. +Add the `defaultValue` setting to your `<input-field>` to define a default value for it. +This value will be imported into the database on installing and updating the plugin. +We use [Symfony\Component\Config\Util\XmlUtils](https://github.com/symfony/config/blob/7.1/Util/XmlUtils.php#L211) for casting the values into the correct PHP types. Below, you'll find an example of how to use this setting. @@ -132,11 +157,27 @@ Below, you'll find an example of how to use this setting. </input-field> ``` -_Please note, `<disabled>` only takes boolean values._ +_Please note, `<disabled>` only accepts boolean values._ + +#### required + +You can add the `<required>` setting to any of your `<input-field>` elements to mark it accordingly. + +Below, you'll find an example of how to use this setting. + +```html +<input-field> + <name>email</name> + <required>true</required> +</input-field> +``` + +_Please note, `<required>` only accepts boolean values._ #### copyable -You can add the `<copyable>` setting to your `<input-field>` which are of type `text` or extensions of it. This will add a button at the right, which on click copies the content of your `<input-field>` into the clipboard. +You can add the `<copyable>` setting to your `<input-field>` which are of type `text` or extensions of it. +This will add a button at the right, which on click copies the content of your `<input-field>` into the clipboard. Below, you'll find an example of how to use this setting. @@ -147,11 +188,42 @@ Below, you'll find an example of how to use this setting. </input-field> ``` -_Please note, that `<copyable>` only takes boolean values_ +_Please note, that `<copyable>` only accepts boolean values_ + +#### Text length restrictions + +You can add the `<minLength>`/`<maxLength>` settings to your `<input-field>` which are of type `text`, `url` or `password`. +With those you can restrict the length of the input. + +Below, you'll find an example of how to use this setting. + +```html +<input-field type="password"> + <name>token</name> + <minLength>5</minLength> + <maxLength>20</maxLength> +</input-field> +``` + +#### Number length restrictions + +You can add the `<min>`/`<max>` settings to your `<input-field>` which are of type `int` or `float`. +With those you can restrict the minimum and maximum value of the input. + +Below, you'll find an example of how to use this setting. + +```html +<input-field type="int"> + <name>token</name> + <min>5</min> + <max>20</max> +</input-field> +``` #### options -You can use `<options>` to add settings to a `<input-field>` of the types `single-select` and `multi-select`. Each `<option>` represents one setting you can select. +You can use `<options>` to add settings to a `<input-field>` of the types `single-select` and `multi-select`. +Each `<option>` represents one setting you can select. Below you'll find an example. @@ -173,11 +245,19 @@ Below you'll find an example. </input-field> ``` -Each `<options>` element must contain at least one `<option>` element. Each `<option>` element must contain at least one `<id>` and one `<name>` element. As you can see above, `<name>` elements are translatable via the `lang` attribute. +Each `<options>` element must contain at least one `<option>` element. +Each `<option>` element must contain at least one `<id>` and one `<name>` element. +As you can see above, `<name>` elements are translatable via the `lang` attribute. ### Advanced custom input fields -For more complex and advanced configurations it is possible to declare a `<component name="componentName">` element. This element can render many admin components. It is also possible to render your own admin component which you could deliver with your plugin. The name of the component has to match the components name in the Administration, for example `sw-entity-single-select`. The component also needs a `<name>` element first. All other elements within the component element will be passed to the rendered admin component as properties. For some components you could also use [`label` and `placeholder`](add-plugin-configuration#label-placeholder-and-help-text). +For more complex and advanced configurations it is possible to declare a `<component name="componentName">` element. +This element can render many admin components. +It is also possible to render your own admin component which you could deliver with your plugin. +The name of the component has to match the components name in the Administration, for example `sw-entity-single-select`. +The component also needs a `<name>` element first. +All other elements within the component element will be passed to the rendered admin component as properties. +For some components you could also use [`label` and `placeholder`](add-plugin-configuration#label-placeholder-and-help-text). Here are some examples: @@ -233,11 +313,15 @@ Stores an array with IDs of the selected products into the system config. </component> ``` -Allows you to edit snippet values within the configuration page. This component does not store values in the system config, but changes the translations for the snippet key. **Note: This field is only available from 6.3.4.0 onward.** +Allows you to edit snippet values within the configuration page. +This component does not store values in the system config, but changes the translations for the snippet key. +**Note: This field is only available from 6.3.4.0 onward.** ### Supported component types -Please Note: It is impossible to allow every component to the config.xml, due to their complexities. If you can't efficiently resolve your plugin's necessities with, it is probably better to create an own module instead. Therefore, Shopware supports the following components by default (also to be found in the [ConfigValidator class](https://github.com/shopware/shopware/blob/729fbf368a065177a17e0fc190334ce02b45f418/src/Core/Framework/App/Validation/ConfigValidator.php#L16)): +Please Note: It is impossible to allow every component in the `config.xml`, due to their complexities. +If you can't efficiently resolve your plugin's necessities with, it is probably better to create an own module instead. +Therefore, Shopware supports the following components by default (also to be found in the [ConfigValidator class](https://github.com/shopware/shopware/blob/v6.6.7.0/src/Core/Framework/App/Validation/ConfigValidator.php#L18)): * sw-entity-single-select * sw-entity-multi-id-select @@ -250,7 +334,7 @@ Please Note: It is impossible to allow every component to the config.xml, due to Now all that's left to do is to present you a working example `config.xml` and show you the result. ```xml -// <plugin root>/src/Resources/config/config.xml +<!--<plugin root>/src/Resources/config/config.xml--> <?xml version="1.0" encoding="UTF-8"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/shopware/shopware/trunk/src/Core/System/SystemConfig/Schema/config.xsd"> @@ -307,8 +391,12 @@ Now all that's left to do is to present you a working example `config.xml` and s ## Add values to your configuration -After adding your input fields to the `config.xml`, you can add values to your configuration. To do so, navigate from the sidebar to the `Extensions` > `My extensions` > `Apps` tab and click on your plugin's `...` button. Now you can see the `Configuration` tab and fill in the values for your input fields. +After adding your input fields to the `config.xml`, you can add values to your configuration. +To do so, navigate from the sidebar to the `Extensions` > `My extensions` > `Apps` tab and click `Configure`. +Now you can see the `Configuration` tab and fill in the values for your input fields. ## Next steps -Now you've added your own plugin configuration. But how do you actually read which configurations the shop owner used? This will be covered in our guide about [Using the plugin configuration](use-plugin-configuration). \ No newline at end of file +Now you've added your own plugin configuration. +But how do you actually read which configurations the shop owner used? +This will be covered in our guide about [Using the plugin configuration](use-plugin-configuration). diff --git a/guides/plugins/plugins/plugin-fundamentals/add-scheduled-task.md b/guides/plugins/plugins/plugin-fundamentals/add-scheduled-task.md index 9511e15fb..6b6b48a5d 100644 --- a/guides/plugins/plugins/plugin-fundamentals/add-scheduled-task.md +++ b/guides/plugins/plugins/plugin-fundamentals/add-scheduled-task.md @@ -89,6 +89,7 @@ Following will be the respective task handler: namespace Swag\BasicExample\Service\ScheduledTask; use Shopware\Core\Framework\MessageQueue\ScheduledTask\ScheduledTaskHandler; +use Symfony\Component\Messenger\Attribute\AsMessageHandler; #[AsMessageHandler(handles: ExampleTask::class)] class ExampleTaskHandler extends ScheduledTaskHandler diff --git a/guides/plugins/plugins/redis.md b/guides/plugins/plugins/redis.md new file mode 100644 index 000000000..1d421c819 --- /dev/null +++ b/guides/plugins/plugins/redis.md @@ -0,0 +1,77 @@ +--- +nav: + title: Redis + position: 45 + +--- + +# Redis + +Starting with Shopware v6.6.8.0, Redis support has been improved, giving you more flexibility in how you use it in your projects and plugins. + +Once you've set up your Redis connections as explained in the [Redis configuration](../../hosting/infrastructure/redis) guide, you can access them in your code using the following methods: + +1. Inject `Shopware\Core\Framework\Adapter\Redis\RedisConnectionProvider` and retrieve connections by name: + + ```xml + <service id="MyCustomService"> + <argument type="service" id="Shopware\Core\Framework\Adapter\Redis\RedisConnectionProvider" /> + <argument>%myservice.redis_connection_name%</argument> + </service> + ``` + + ```php + class MyCustomService + { + public function __construct ( + private RedisConnectionProvider $redisConnectionProvider, + string $connectionName, + ) { } + + public function doSomething() + { + if ($this->redisConnectionProvider->hasConnection($this->connectionName)) { + $connection = $this->redisConnectionProvider->getConnection($this->connectionName); + // use connection + } + } + } + ``` + +2. Use `Shopware\Core\Framework\Adapter\Redis\RedisConnectionProvider` as factory to define custom services: + + ```xml + <service id="my.custom.redis_connection" class="Redis"> + <factory service="Shopware\Core\Framework\Adapter\Redis\RedisConnectionProvider" method="getConnection" /> + <argument>%myservice.redis_connection_name%</argument> + </service> + + <service id="MyCustomService"> + <argument type="service" id="my.custom.redis_connection" /> + </service> + ``` + + ```php + class MyCustomService + { + public function __construct ( + private Redis $redisConnection, + ) { } + + public function doSomething() + { + // use connection + } + } + ``` + This approach is especially useful when you want multiple services to share the same Redis connection. + +3. Inject connection directly by name: + ```xml + <service id="MyCustomService"> + <argument type="service" id="shopware.redis.connection.connection_name" /> + </service> + ``` + Be cautious with this approach! If you change the Redis connection names in your configuration, it will cause container build errors. + +Keep in mind that Redis is an optional dependency in Shopware and might not be available in all installations. diff --git a/guides/plugins/plugins/storefront/add-custom-page.md b/guides/plugins/plugins/storefront/add-custom-page.md index 61c77300e..6b9049309 100644 --- a/guides/plugins/plugins/storefront/add-custom-page.md +++ b/guides/plugins/plugins/storefront/add-custom-page.md @@ -45,7 +45,7 @@ class ExampleController extends StorefrontController It has a method `examplePage`, which is accessible via the route `example-page`. This method will be responsible for loading your page later on, but we'll leave it like that for now. -Don't forget to [register your controller via the DI](add-custom-controller#Services.xml%20example). +Don't forget to [register your controller via the DI](add-custom-controller#services-xml-example). ### Creating the pageloader @@ -162,6 +162,23 @@ class ExampleController extends StorefrontController Note, that we've added the page to the template variables. +#### Adjusting the services.xml + +In addition, it is necessary to pass the argument with the ID of the `ExamplePageLoader` class to the [configuration ](add-custom-controller#services-xml-example) of the controller service in the `services.xml`. + +```html +// <plugin root>/src/Resources/config/services.xml +<service id="Swag\BasicExample\Storefront\Controller\ExampleController" public="true"> + <argument type="service" id="Swag\BasicExample\Storefront\Page\Example\ExamplePageLoader" /> + <call method="setContainer"> + <argument type="service" id="service_container"/> + </call> + <call method="setTwig"> + <argument type="service" id="twig"/> + </call> +</service> +``` + ### Creating the example page So now we're going to create the example page class, that was already used in our page loader, `ExamplePage`. @@ -195,7 +212,7 @@ class ExamplePage extends Page } ``` -As explained in the page loader section, your page can contain all kinds of custom data. It has to provide a getter and a setter for the custom data, so it can be applied and read. In this example, the entity from our guide about [creating custom complex data](../framework/data-handling/add-custom-complex-data#Entity%20class) is being used. +As explained in the page loader section, your page can contain all kinds of custom data. It has to provide a getter and a setter for the custom data, so it can be applied and read. In this example, the entity from our guide about [creating custom complex data](../framework/data-handling/add-custom-complex-data#entity-class) is being used. And that's it already. Your page is ready to go. diff --git a/guides/plugins/plugins/storefront/add-scss-variables-via-subscriber.md b/guides/plugins/plugins/storefront/add-scss-variables-via-subscriber.md index 83f59c6f7..541157e21 100644 --- a/guides/plugins/plugins/storefront/add-scss-variables-via-subscriber.md +++ b/guides/plugins/plugins/storefront/add-scss-variables-via-subscriber.md @@ -49,7 +49,7 @@ You can add a new subscriber according to the [Listening to events](../plugin-fu namespace Swag\BasicExample\Subscriber; -use Shopware\Storefront\Event\ThemeCompilerEnrichScssVariablesEvent; +use Shopware\Storefront\Theme\Event\ThemeCompilerEnrichScssVariablesEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class ThemeVariableSubscriber implements EventSubscriberInterface diff --git a/guides/plugins/plugins/storefront/add-translations.md b/guides/plugins/plugins/storefront/add-translations.md index 3dd141802..491d7bb8d 100644 --- a/guides/plugins/plugins/storefront/add-translations.md +++ b/guides/plugins/plugins/storefront/add-translations.md @@ -9,35 +9,48 @@ nav: ## Overview -In this guide you'll learn how to add translations to the Storefront and how to use them in your twig templates. To organize your snippets you can add them to `.json` files, so structuring and finding snippets you want to change is very easy. +In this guide, you'll learn how to add translations to the Storefront and how to use them in your twig templates. +To organize your snippets you can add them to `.json` files, so structuring and finding snippets you want to change is very easy. ## Prerequisites -To add your own custom translations for your plugin or app, you first need a base. Refer to either the [Plugin Base Guide](../plugin-base-guide) or the [App Base Guide](../../apps/app-base-guide) to create one. +To add your own custom translations for your plugin or app, you first need a base. +Refer to either the [Plugin Base Guide](../plugin-base-guide) or the [App Base Guide](../../apps/app-base-guide) to create one. ## Snippet file structure -Shopware 6 automatically loads your snippet files when a standard file structure and a naming convention are followed. To do so, store your snippet files in the `<extension root>/src/Resources/snippet/<locale>/` directory of your extension. Also, you can further use subdirectories if you want to. Use `<name>.<locale>` as the naming pattern. The name can be freely defined, while the locale must map to the ISO string of the supported locale in this snippet file - for example `example.de-DE.json`. +Shopware 6 automatically loads your snippet files when a standard file structure and a naming convention are followed. +To do so, store your snippet files in the `<extension root>/src/Resources/snippet/` directory of your plugin or `<extension root>/Resources/snippet/` for your app or theme. +Also, you can use further subdirectories if you want to. +Use `<name>.<locale>` as the naming pattern for the file. +The name can be freely defined, while the locale **must** map to the ISO string of the supported locale in this snippet file - for example `example.de-DE.json`. +More precisely, the ISO string is a combination of "ISO 639-1" language codes and "ISO 3166-1 alpha-2" country codes. +Later, this will be converted to the ICU format (`de_DE`), which is also used by [Symfony](https://symfony.com/doc/current/reference/constraints/Locale.html). -In case you want to provide base translations (ship translations for a whole new language), indicate it with the suffix `.base` in your file name. Now the filename convention to be followed looks like this `<name>.<locale>.base.json` - for example, `example.de-AT.base.json`. +In case you want to provide base translations (ship translations for a whole new language), indicate it with the suffix `.base` in your file name. +Now the filename convention to be followed looks like this `<name>.<locale>.base.json` - for example, `example.de-AT.base.json`. So your structure could then look like this: ```text └── SwagBasicExample - └── src + └── src // Without `src` in apps / themes ├─ Resources │ └─ snippet - │ ├─ de_DE - │ │ └─ example.de-DE.json - │ └─ en_GB + │ ├─ example.de-DE.json + │ └─ some-directory // optional │ └─ example.en-GB.json └─ SwagBasicExample.php ``` -## Creating the translation +## Creating translations -Now that we know how the structure of snippets should be, we can create a new snippet file. In this example we are creating a snippet file for British English called `example.en-GB.json`. If you are using nested objects, you can access the values with `exampleOne.exampleTwo.exampleThree`. We can also use template variables, which we can assign values later in the template. There is no explicit syntax for variables in the Storefront. However, it is recommended to enclose them with `%` symbols to make their purpose clear. +Now that we know how the structure of snippets should be, we can create a new snippet file. +In this example we are creating a snippet file for British English called `example.en-GB.json`. +If you are using nested objects, you can access the values with `exampleOne.exampleTwo.exampleThree`. +We can also use template variables, which we can assign values later in the template. +There is no explicit syntax for variables in the Storefront. +However, it is recommended to enclose them with `%` symbols to make their purpose clear. Here's an example of an English translation file: @@ -51,9 +64,10 @@ Here's an example of an English translation file: } ``` -## Using the translation in templates +## Using translations in templates -Now we want to use our previously created snippet in our twig template, we can do this with the `trans` filter. Below you can find two examples where we use our translation with placeholders and without. +Now we want to use our previously created snippet in our twig template, we can do this with the `trans` filter. +Below, you can find two examples where we use our translation with placeholders and without. Translation without placeholders: @@ -71,9 +85,11 @@ Translation with placeholders: </div> ``` -## Using the translation in controllers +## Using translations in controllers -If we want to use our snippet in a controller, we have to use the `trans` function. Note that we have to extend our class from `Shopware\Storefront\Controller\StorefrontController`. +If we want to use our snippet in a controller, we can use the `trans` method, +which is available if our class is extending from `Shopware\Storefront\Controller\StorefrontController`. +Or use injection via [DI container](#using-translation-generally-in-php). Translation without placeholders: @@ -87,9 +103,11 @@ Translation with placeholders: $this->trans('soldProducts', ['%count%' => 3, '%country%' => 'Germany']); ``` -## Using translation generally in PHP +## General usage of translations in PHP -If we need to use a snippet elsewhere in PHP, we can use [Dependency Injection](../plugin-fundamentals/dependency-injection) to inject the `translator`, which implements Symfony's `Symfony\Contracts\Translation\TranslatorInterface`: +If we need to use a snippet elsewhere in PHP, +we can use [Dependency Injection](../plugin-fundamentals/dependency-injection) to inject the `translator` service, +which implements Symfony's `Symfony\Contracts\Translation\TranslatorInterface`: ```xml <service id="Swag\Example\Service\SwagService" public="true" > @@ -106,7 +124,7 @@ public function __construct(TranslatorInterface $translator) } ``` -Your class can then use translation similarly to controllers: +Then, call the `trans` method, which has the same parameters as the method from controllers. ```php $this->translator->trans('soldProducts', ['%count%' => 3, '%country%' => 'Germany']); diff --git a/guides/plugins/themes/add-theme-inheritance.md b/guides/plugins/themes/add-theme-inheritance.md index ed4efcff3..3653c4de8 100644 --- a/guides/plugins/themes/add-theme-inheritance.md +++ b/guides/plugins/themes/add-theme-inheritance.md @@ -89,7 +89,7 @@ Here is an example: "configInheritance": [ "@Storefront", "@SwagBasicExampleTheme" -] + ] } ``` diff --git a/resources/accessibility/storefront/index.md b/resources/accessibility/storefront/index.md index 33d4117cf..39acf0832 100644 --- a/resources/accessibility/storefront/index.md +++ b/resources/accessibility/storefront/index.md @@ -97,22 +97,48 @@ If the block `component_list_items` is being extended, the new accessibility cha ## Overview of accessibility issues for iteration 1 -We list our current accessibility issues with their state of implementation in the following ticket: [NEXT-37039](https://issues.shopware.com/issues/NEXT-37039) -This ticket has an up-to-date overview. -Below, we will update the current states with more additional information about the implementation, but this can be lagging a view days behind. +::: info +With accessibility iteration 1 we have addressed the most critical accessibility problems and implemented multiple improvements. +You can find an overview of the accessibility iteration 1 epic in the following ticket: [NEXT-37039](https://issues.shopware.com/issues/NEXT-37039) +::: + +### Continuous efforts to ensure accessibility + +We are continuously testing our core Storefront to meet accessibility requirements. This includes screen reader usage, keyboard-operation or color contrast analyzes. +We are using the [WCAG 2.1 Level AA](https://www.w3.org/TR/WCAG21/) standard and do our best to solve all issues to meet the WCAG 2.1 requirements. ### Overview of released accessibility improvements * Below, you find a list of recent accessibility improvements. The list includes a changelog and the release versions for each improvement. * Enable the feature flag `ACCESSIBILITY_TWEAKS` to activate all breaking accessibility changes. -| Issue key | Topic | Breaking changes | Changelog | Release versions | -|-------------------------------------------------------------|------------------------------------------------------------|------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------| -| [NEXT-33694](https://issues.shopware.com/issues/NEXT-33694) | Change shipping toggle in OffCanvas cart to button element | No | [Changelog](https://github.com/shopware/shopware/blob/v6.6.2.0/changelog/release-6-6-2-0/2024-04-17-change-shipping-costs-toggle-to-button-element.md) | [v6.6.2.0](https://github.com/shopware/shopware/releases/tag/v6.6.2.0) | -| [NEXT-35318](https://issues.shopware.com/issues/NEXT-35318) | Add heading elements for account login page | No | [Changelog](https://github.com/shopware/shopware/blob/v6.6.2.0/changelog/release-6-6-2-0/2024-04-15-heading-elements-on-registration-page.md) | [v6.6.2.0](https://github.com/shopware/shopware/releases/tag/v6.6.2.0) | -| [NEXT-34423](https://issues.shopware.com/issues/NEXT-33684) | No empty nav element in top-bar | Yes | [Changelog](https://github.com/shopware/shopware/blob/v6.6.1.0/changelog/release-6-6-1-0/2023-03-05-no-empty-nav.md) | [v6.6.1.0](https://github.com/shopware/shopware/releases/tag/v6.6.1.0) | -| [NEXT-33682](https://issues.shopware.com/issues/NEXT-33682) | Provide distinctive document titles for each page | No | [Changelog](https://github.com/shopware/shopware/blob/v6.6.1.0/changelog/release-6-6-1-0/2024-03-12-distinctive-document-titles.md) | [v6.6.1.0](https://github.com/shopware/shopware/releases/tag/v6.6.1.0) | | -| [NEXT-33879](https://issues.shopware.com/issues/NEXT-33879) | A closing mechanism for the navigation | No | [Changelog](https://github.com/shopware/shopware/blob/trunk/changelog/2024-05-03-esc-key-for-nav-flyout-close.md) | [v6.6.3.0](https://github.com/shopware/shopware/releases/tag/v6.6.3.0) | +| Issue key | Topic | Breaking changes | Changelog | Release versions | +|---------------------------------------------------------------|-------------------------------------------------------------------------------------------------|------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------| +| [NEXT-33689](https://issues.shopware.com/issues/NEXT-33689) | Missing semantic markup of form address headings | No | [Changelog](https://github.com/shopware/shopware/blob/v6.6.6.0/changelog/release-6-6-6-0/2024-08-13-registration-form-fieldset-improvement.md) | [v6.6.6.0](https://github.com/shopware/shopware/releases/tag/v6.6.6.0) | +| [NEXT-33693](https://issues.shopware.com/issues/NEXT-33693) | Product image zoom modal keyboard accessibility | No | [Changelog](https://github.com/shopware/shopware/blob/v6.6.6.0/changelog/release-6-6-6-0/2024-08-08-improve-image-zoom-modal-accessibility.md) | [v6.6.6.0](https://github.com/shopware/shopware/releases/tag/v6.6.6.0) | +| [NEXT-33697](https://issues.shopware.com/issues/NEXT-33697) | Focused slides in the carousel are not being moved into the visible area | Yes | [Changelog](https://github.com/shopware/shopware/blob/v6.6.6.0/changelog/release-6-6-6-0/2024-08-05-improve-slider-element-accessibility.md) | [v6.6.6.0](https://github.com/shopware/shopware/releases/tag/v6.6.6.0) | +| [NEXT-33696](https://issues.shopware.com/issues/NEXT-33696) | Focus jumps to the top of the page after closing a modal | No | [Changelog](https://github.com/shopware/shopware/blob/v6.6.6.0/changelog/release-6-6-6-0/2024-08-01-add-focus-handling-to-storefront.md) | [v6.6.6.0](https://github.com/shopware/shopware/releases/tag/v6.6.6.0) | +| [NEXT-26680](https://issues.shopware.com/issues/NEXT-26680) | Ensure that resizing content up to 200% does not cause breaks | Yes | [Changelog](https://github.com/shopware/shopware/blob/v6.6.6.0/changelog/release-6-6-6-0/2024-08-13-Improved-storefront-text-scaling.md) | [v6.6.6.0](https://github.com/shopware/shopware/releases/tag/v6.6.6.0) | +| [NEXT-26714](https://issues.shopware.com/issues/NEXT-26714) | Language of each Storefront passage or phrase in the content can be programmatically determined | No | [Changelog](https://github.com/shopware/shopware/blob/v6.6.6.0/changelog/release-6-6-6-0/2024-08-05-add-language-to-reviews.md) | [v6.6.6.0](https://github.com/shopware/shopware/releases/tag/v6.6.6.0) | +| [NEXT-34090](https://issues.shopware.com/issues/NEXT-34090) | Check Lighthouse Accessibility Score | No | [Changelog](https://github.com/shopware/shopware/blob/v6.6.6.0/changelog/release-6-6-6-0/2024-08-21-fix-scroll-up-button-accessibility.md) | [v6.6.6.0](https://github.com/shopware/shopware/releases/tag/v6.6.6.0) | +| [NEXT-28114](https://issues.shopware.com/issues/NEXT-28114) | Pagination does not have links | Yes | [Changelog](https://github.com/shopware/shopware/blob/v6.6.6.0/changelog/release-6-6-6-0/2023-08-31-pagination-with-links.md) | [v6.6.6.0](https://github.com/shopware/shopware/releases/tag/v6.6.6.0) | +| [NEXT-33682](https://issues.shopware.com/issues/NEXT-33682) | Non-informative document title | No | [Changelog](https://github.com/shopware/shopware/blob/v6.6.1.0/changelog/release-6-6-1-0/2024-03-12-distinctive-document-titles.md) | [v6.6.6.0](https://github.com/shopware/shopware/releases/tag/v6.6.1.0) | +| [NEXT-33695](https://issues.shopware.com/issues/NEXT-33695) | The form element quantity selector is not labeled | No | [Changelog](https://github.com/shopware/shopware/blob/v6.6.5.0/changelog/release-6-6-5-0/2024-07-15-the-form-element-quantity-selector-is-not-labeled.md) | [v6.6.5.0](https://github.com/shopware/shopware/releases/tag/v6.6.5.0) | +| [NEXT-33675](https://issues.shopware.com/issues/NEXT-33675) | Slider reports confusing status changes to screen readers | No | [Changelog](https://github.com/shopware/shopware/blob/v6.6.4.0/changelog/release-6-6-4-0/2024-05-31-remove-unwanted-aria-live-attributes-from-sliders.md) | [v6.6.4.0](https://github.com/shopware/shopware/releases/tag/v6.6.4.0) | +| [NEXT-26682](https://issues.shopware.com/issues/NEXT-26682) | The user needs to be able to close triggered, additional content | No | [Changelog](https://github.com/shopware/shopware/blob/trunk/changelog/release-6-6-3-0/2024-05-03-esc-key-for-nav-flyout-close.md) | [v6.6.3.0](https://github.com/shopware/shopware/releases/tag/v6.6.3.0) | +| [NEXT-33879](https://issues.shopware.com/issues/NEXT-33879) | Close navigation flyout with escape key | No | [Changelog](https://github.com/shopware/shopware/blob/trunk/changelog/release-6-6-3-0/2024-05-03-esc-key-for-nav-flyout-close.md ) | [v6.6.3.0](https://github.com/shopware/shopware/releases/tag/v6.6.3.0) | +| [NEXT-33683](https://issues.shopware.com/issues/NEXT-33683) | Improve "Remove Product" button labeling in checkout | No | [Changelog](https://github.com/shopware/shopware/blob/v6.6.3.0/changelog/release-6-6-3-0/2024-05-03-improve-line-item-labels-and-alt-texts.md) | [v6.6.3.0](https://github.com/shopware/shopware/releases/tag/v6.6.3.0) | +| [NEXT-33685](https://issues.shopware.com/issues/NEXT-33685) | Missing alternative text for product images in the shopping cart | No | [Changelog](https://github.com/shopware/shopware/blob/v6.6.3.0/changelog/release-6-6-3-0/2024-05-03-improve-line-item-labels-and-alt-texts.md) | [v6.6.3.0](https://github.com/shopware/shopware/releases/tag/v6.6.3.0) | +| [NEXT-33879](https://issues.shopware.com/issues/NEXT-33879) | A closing mechanism for the navigation | No | [Changelog](https://github.com/shopware/shopware/blob/trunk/changelog/2024-05-03-esc-key-for-nav-flyout-close.md) | [v6.6.3.0](https://github.com/shopware/shopware/releases/tag/v6.6.3.0) | +| [NEXT-33694](https://issues.shopware.com/issues/NEXT-33694) | Change shipping toggle in OffCanvas cart to button element | No | [Changelog](https://github.com/shopware/shopware/blob/v6.6.2.0/changelog/release-6-6-2-0/2024-04-17-change-shipping-costs-toggle-to-button-element.md) | [v6.6.2.0](https://github.com/shopware/shopware/releases/tag/v6.6.2.0) | +| [NEXT-35318](https://issues.shopware.com/issues/NEXT-35318) | Add heading elements for account login page | No | [Changelog](https://github.com/shopware/shopware/blob/v6.6.2.0/changelog/release-6-6-2-0/2024-04-15-heading-elements-on-registration-page.md) | [v6.6.2.0](https://github.com/shopware/shopware/releases/tag/v6.6.2.0) | +| [NEXT-33682](https://issues.shopware.com/issues/NEXT-33682) | Provide distinctive document titles for each page | No | [Changelog](https://github.com/shopware/shopware/blob/v6.6.1.0/changelog/release-6-6-1-0/2024-03-12-distinctive-document-titles.md) | [v6.6.1.0](https://github.com/shopware/shopware/releases/tag/v6.6.1.0) | +| [NEXT-34423](https://issues.shopware.com/issues/NEXT-33684) | No empty nav element in top-bar | Yes | [Changelog](https://github.com/shopware/shopware/blob/v6.6.1.0/changelog/release-6-6-1-0/2023-03-05-no-empty-nav.md) | [v6.6.1.0](https://github.com/shopware/shopware/releases/tag/v6.6.1.0) | +| [NEXT-26712](https://issues.shopware.com/issues/NEXT-26712) | Update the focus states so that they are clearly visible | No | [Multiple changes](https://github.com/search?q=repo%3Ashopware%2Fshopware+NEXT-26712&type=commits) | [Multiple releases](https://github.com/search?q=repo%3Ashopware%2Fshopware+NEXT-26712&type=code) | +| [NEXT-26717](https://issues.shopware.com/issues/NEXT-26717) | Increase compatibility of Storefront with future assistance technologies | No | [Multiple changes](https://github.com/search?q=repo%3Ashopware%2Fshopware+NEXT-26717&type=commits) | [Multiple releases](https://github.com/search?q=repo%3Ashopware%2Fshopware+NEXT-26717&type=code) | +| [NEXT-26705](https://issues.shopware.com/issues/NEXT-26705) | Content functionality operable through keyboard | Yes | [Multiple changes](https://github.com/search?q=repo%3Ashopware%2Fshopware+NEXT-26705&type=commits) | [Multiple releases](https://github.com/search?q=repo%3Ashopware%2Fshopware+NEXT-26705&type=code) | +| [NEXT-26707](https://issues.shopware.com/issues/NEXT-26707) | No keyboard traps should occur in the Storefront | - | Verification work without released code changes | - | +| [NEXT-26709](https://issues.shopware.com/issues/NEXT-26709) | Mechanism for the user to pause, stop, or hide moving content | - | Verification work without released code changes | - | ### Overview of known accessibility issues @@ -121,30 +147,10 @@ Please note that only issues that are completely resolved and already released i The list below will include tickets that are already in progress or finished but not released yet. The list also includes checking and evaluation work. You can see the current status via the links to the issue tracker. ::: -| Issue key | Topic | -|-------------------------------------------------------------|-------------------------------------------------------------------------------------------------| -| [NEXT-33675](https://issues.shopware.com/issues/NEXT-33675) | Slider reports confusing status changes to screen readers | -| [NEXT-33683](https://issues.shopware.com/issues/NEXT-33683) | Improve "Remove Product" button labeling in checkout | -| [NEXT-33685](https://issues.shopware.com/issues/NEXT-33685) | Missing alternative text for product images in the shopping cart | -| [NEXT-33689](https://issues.shopware.com/issues/NEXT-33689) | Missing semantic markup of form address headings | -| [NEXT-33693](https://issues.shopware.com/issues/NEXT-33693) | Product image zoom modal keyboard accessibility | -| [NEXT-33695](https://issues.shopware.com/issues/NEXT-33695) | The form element quantity selector is not labeled | -| [NEXT-33696](https://issues.shopware.com/issues/NEXT-33696) | Focus jumps to the top of the page after closing a modal | -| [NEXT-33697](https://issues.shopware.com/issues/NEXT-33697) | Focused slides in the carousel are not being moved into the visible area | -| [NEXT-33879](https://issues.shopware.com/issues/NEXT-33879) | Close navigation flyout with escape key | -| [NEXT-26677](https://issues.shopware.com/issues/NEXT-26677) | Check if all non-text content has text alternative and provide if necessary | -| [NEXT-26679](https://issues.shopware.com/issues/NEXT-26679) | Add text to components that only work with icons to identify their purpose | -| [NEXT-26680](https://issues.shopware.com/issues/NEXT-26680) | Ensure that resizing content up to 200% does not cause breaks | -| [NEXT-26682](https://issues.shopware.com/issues/NEXT-26682) | The user needs to be able to close triggered, additional content | -| [NEXT-26705](https://issues.shopware.com/issues/NEXT-26705) | Content functionality operable through keyboard | -| [NEXT-26707](https://issues.shopware.com/issues/NEXT-26707) | No keyboard traps should occur in the Storefront | -| [NEXT-26709](https://issues.shopware.com/issues/NEXT-26709) | Mechanism for the user to pause, stop, or hide moving content | -| [NEXT-26715](https://issues.shopware.com/issues/NEXT-26715) | Provide error correction suggestions | -| [NEXT-26712](https://issues.shopware.com/issues/NEXT-26712) | Update the focus states so that they are clearly visible | -| [NEXT-26714](https://issues.shopware.com/issues/NEXT-26714) | Language of each Storefront passage or phrase in the content can be programmatically determined | -| [NEXT-26717](https://issues.shopware.com/issues/NEXT-26717) | Increase compatibility of Storefront with future assistance technologies | -| [NEXT-33807](https://issues.shopware.com/issues/NEXT-33807) | Text styles needs to be adjusted (line height, paragraph spacing) | -| [NEXT-34090](https://issues.shopware.com/issues/NEXT-34090) | Check Lighthouse Accessibility Score | -| [NEXT-36116](https://issues.shopware.com/issues/NEXT-36116) | Keyboard/Tabs should work for nav main-navigation-menu | -| [NEXT-21474](https://issues.shopware.com/issues/NEXT-21474) | Pagination does not have links | -| [NEXT-33682](https://issues.shopware.com/issues/NEXT-33682) | Non-informative document title | +| Issue key | Topic | Notes | +|-------------------------------------------------------------|-----------------------------------------------------------------------------|-------------------| +| [NEXT-26679](https://issues.shopware.com/issues/NEXT-26679) | Add text to components that only work with icons to identify their purpose | Unreleased | +| [NEXT-26677](https://issues.shopware.com/issues/NEXT-26677) | Check if all non-text content has text alternative and provide if necessary | Unreleased | +| [NEXT-26715](https://issues.shopware.com/issues/NEXT-26715) | Provide error correction suggestions | Unreleased | +| [NEXT-33807](https://issues.shopware.com/issues/NEXT-33807) | Text styles needs to be adjusted (line height, paragraph spacing) | Unreleased | +| [NEXT-36116](https://issues.shopware.com/issues/NEXT-36116) | Keyboard/Tabs should work for nav main-navigation-menu | Unreleased | diff --git a/resources/guidelines/testing/Differentiator-Clusters.md b/resources/guidelines/testing/Differentiator-Clusters.md index f5534cbc2..1ef426389 100644 --- a/resources/guidelines/testing/Differentiator-Clusters.md +++ b/resources/guidelines/testing/Differentiator-Clusters.md @@ -1,48 +1,48 @@ -# Differentiator cluster for Shopware extensions +# Differentiator cluster for Shopware plugins or apps This section will show you the new differentiator groups which needs to be fulfilled to be to released to the store . ## Cluster variations -* Cluster 1: Your extension offers meaningful use cases that cannot be replicated with other comparable extensions. Additionally, it provides a meaningful integration that is not implemented in the comparison extension. +* Cluster 1: Your plugin or app offers meaningful use case that cannot be replicated with other comparable plugins or apps. Additionally, it provides a meaningful integration that is not implemented in the comparison plugin or app. -* Cluster 2: Your extension offers meaningful use cases that cannot be replicated with other comparable extensions. Moreover, it works sensibly with the Shopware standard, instead of using its own technical approaches. +* Cluster 2: Your plugin or app offers meaningful use case that cannot be replicated with other comparable plugins or apps. Moreover, it works sensibly with Shopware standards, instead of using its own technical approaches. -* Cluster 3: Your extension is based on the app system and offers a meaningful integration that is not implemented in the comparison extension. +* Cluster 3: Your app is based on the app system and offers a meaningful integration that is not implemented in the comparison app. -* Cluster 4: Your extension is based on the app system and offers meaningful use cases that cannot be replicated with other comparable extensions. +* Cluster 4: Your app is based on the app system and offers meaningful use cases that cannot be replicated with other comparable apps. ## Examples of meaningful use of the Shopware standard * Uses custom fields instead of own tables. This facilitates data management and querying and avoids inconsistencies or conflicts with the Shopware data model. -* Uses Admin SDK instead of own modules. This allows for seamless integration of the extensions into the Shopware admin interface. +* Uses Admin SDK instead of own modules. This allows for seamless integration of the plugins or apps into the Shopware admin interface. * Offers a headless solution. This enables Shopware to be used as a backend for any frontend applications that can communicate with Shopware via the API. -* Offers a reasonable API connection. This means that the extension uses the Shopware API in a compliant and efficient manner to exchange, update, or manipulate data. +* Offers a reasonable API connection. This means that the plugin or app uses the Shopware API in a compliant and efficient manner to exchange, update, or manipulate data. -* Precisely adapts to Shopware externally. This means that the extension complements or extends the appearance of the Shopware admin interface without disturbing or altering it, by using the same styles and elements. +* Precisely adapts to Shopware externally. This means that the plugin or app complements or extends the appearance of the Shopware admin interface without disturbing or altering it, by using the same styles and elements. -## Examples of meaningful use cases that cannot be represented with other extensions +## Examples of meaningful use cases that cannot be represented with other plugins or apps * Offers the possibility to send automatic emails to customers or partners to inform them about important information or offers. -* Offers the possibility to combine the function of the extension with variants. +* Offers the possibility to combine the function of the plugin or app with variants. -* Offers the possibility to link the function of your extension with advanced pricing to enable flexible pricing or discounts. +* Offers the possibility to link the function of your plugin or app with advanced pricing to enable flexible pricing or discounts. * Offers different configurations for different sales channels. ## Examples of Shopware integrations: -* The extension has meaningfully integrated the Rule Builder into the extension. +* The plugin or app has meaningfully integrated the Rule Builder into the plugin or app. -* The extension has meaningfully integrated the Dynamic Product Stream into the extension. +* The plugin or app has meaningfully integrated the Dynamic Product Stream into the plugin or app. -* The extension has meaningfully integrated the Shopware webhook integration into the extension. +* The plugin or app has meaningfully integrated the Shopware webhook integration into the plugin or app. -* The extension has meaningfully integrated the Flow Builder into the extension. +* The plugin or app has meaningfully integrated the Flow Builder into the plugin or app. diff --git a/resources/guidelines/testing/store/index.md b/resources/guidelines/testing/store/index.md index bd155c548..4e4737d7e 100644 --- a/resources/guidelines/testing/store/index.md +++ b/resources/guidelines/testing/store/index.md @@ -7,7 +7,7 @@ nav: # Testing Guidelines for Shopware Extensions -This section guides you with the criteria used to test your extension. Detailed information is available on [quality guidelines for apps](../store/quality-guidelines-apps/),[quality guidelines for plugins](../store/quality-guidelines-plugins/) and [differentiator cluster](../testing/differentiator-cluster/). +This section guides you with the criteria used to test your extension. Detailed information is available on [quality guidelines for apps](../store/quality-guidelines-apps/),[quality guidelines for plugins](../store/quality-guidelines-plugins/) and [differentiator cluster](../Differentiator-Clusters.html). Check out the points that affect your extension and go through them before submitting it for testing. diff --git a/resources/guidelines/testing/store/quality-guidelines-apps/index.md b/resources/guidelines/testing/store/quality-guidelines-apps/index.md index 79175ee28..510a4390f 100644 --- a/resources/guidelines/testing/store/quality-guidelines-apps/index.md +++ b/resources/guidelines/testing/store/quality-guidelines-apps/index.md @@ -1,120 +1,100 @@ --- nav: - title: Quality guidelines for apps in app system + title: Quality guidelines for apps in the plugin system position: 10 --- -# Quality Guidelines for Apps and Themes based on App System in Shopware Store +# Quality Guidelines for the Plugin System in the Shopware Store > **Changelog** +> +>> 09/11/24: Quality guidelines for apps and themes based on app system. +> >> 23/11/23: [Added - New rules for Checklist for app testing](#every-app-based-on-the-app-system) > >> 27/09/23: [Added - Identical name rule](#every-app-based-on-the-app-system) > >> 26/07/23: [Added - Name preset according to new naming scheme](#every-app-based-on-the-app-system) -> ->> 18/07/23: [Compiled code.](../quality-guidelines-apps/#checklist-for-app-testing) -> ->> 12/04/23: [Check for a functional comparison with functions from the Rise or above edition.](../quality-guidelines-apps/#every-app-based-on-the-app-system) -> ->> 14/02/23: [Added new STP tracking - External technology apps/STP apps.](../quality-guidelines-apps/#external-technology-shopware-technology-partner-stp-apps) -> ->> 28/10/21: [Added - Safe your app idea and get a preview in the store.](../quality-guidelines-apps/#every-app-based-on-the-app-system) -> ->> 06/08/21: [Added - Useful links and tutorials for creating an app.](../quality-guidelines-apps/#useful-links-and-tutorials-for-creating-an-app) -> ->> 08/06/21: [Added URL and info regarding the docker environment we use for testing SW6 apps.](../quality-guidelines-apps/#the-way-we-test-apps-based-on-the-app-system) -> ->> 07/06/21: [Template Tests - Now using Scheme.org Structured Data Testing tool instead of Google Structured Testing tool.](../quality-guidelines-apps/#theme-apps) -> ->> 07/06/21: [Account app description - Subprocessor and/or Further subprocessor information may be required for your app.](../quality-guidelines-apps/#app-descriptions-in-your-shopware-account) -> ->> 17/04/21: Restructured the quality guidelines. No new content added. -> ->> 12/05/20: [Added app checklist for your quality assurance.](../quality-guidelines-apps/#checklist-for-app-testing) -> ->> 22/04/20: [Menu entries in the main menu of the Administration are not allowed anymore because of look and feel.](../quality-guidelines-apps/#menu-entries-in-the-main-menu-not-allowed) -## The way we test apps based on the app system +## The way we test apps and themes based on the app system -It is always a good idea to review the process of how we conduct tests prior to submitting your app for review. This ensures the quickest way for your app to be published. +It is always a good idea to review our test process before submitting your app for review. +This ensures the quickest way for your app to be published. We perform the *first test*, and if successful, we do the *follow-up test* again with the most current Shopware version. -The Shopware installation is located in a subfolder. It has a language sub-shop/sales channel with a virtual URL as well as an independent sub-shop/sales channel with its own URL, also located in a subfolder. E.g. `myshop.com/subfolder/backend` or `myshop.com/public/admin`. The app must neither produce any error messages in the backend nor in the frontend. +The Shopware installation is located in a subfolder. +It has a language sub-shop/sales channel with a virtual URL as well as an independent sub-shop/sales channel with its own URL, also located in a subfolder. +E.g. `myshop.com/public/admin`. +The app must neither produce any error messages in the administration nor in the frontend. -The app is tested with the latest official Shopware 6 CE Version. Our testing environment is built with the following components: Nginx Webserver, PHP 7.4 as FPM, MariaDB latest, Shopware installed in subfolder `/shop/public`, default Shopware language *Dutch*. -The environment is built using Docker and is published on Docker Hub. You can use the following command to run it on your system: - -```markdown -docker run --rm -p 80:80 -e VIRTUAL_HOST=localhost ghcr.io/shopwarelabs/testenv:6.X.X -``` +The app is tested with the latest official Shopware 6 CE Version. ::: info -**The shop will be accessible at:** `http://localhost/shop/public` -**Admin-User:** demo -**Admin-Password:** demodemo +We always test with the [actual SW6 version](https://www.shopware.com/de/download/#shopware-6). +So set it to the actual SW6 version e.g., shopware/testenv:6.6.6. +Always test with the app`s highest supported Shopware version. ::: -::: info -We always test with the [actual SW6 version](https://www.shopware.com/de/download/#shopware-6). So set it to the actual SW6 version e.g., `shopware/testenv:6.4.3`. Always test with the app`s highest supported Shopware version. -::: +[Test your app for the Shopware Store (DE):](https://www.youtube.com/watch?v=gLb5CmOdi4g) and EN version is coming soon. **Progressive Web App:** If your app is PWA compatible and you would like the PWA flag, please contact us at [alliances@shopware.com](mailto:alliances@shopware.com). -### Useful links and tutorials for creating an app - -* [Sample app development template](https://github.com/shopwareLabs/AppExample) -* [App base guide](/docs/guides/plugins/apps/app-base-guide) -* [Storefront](../../../../../guides/plugins/apps/storefront/index.md) -* [Admin](../../../../../guides/plugins/apps/administration/index.md) - ## Checklist for app testing -Be sure to use the most recent testing checklist from Shopware and not from any other provider. Pay attention to every single point given below in this guide, as this will be reviewed by us in order to release your app. - -### Every app based on the app system - -* If you are using external fonts (e.g., from Google fonts) or external services, the app store description must contain this information. Please be aware that you might have to edit your *data protection information*. This info could be otherwise placed as a tooltip near the font settings of the app configuration. +Could you be sure to use the most recent testing checklist from Shopware and not any other provider? +Please pay attention to every point in this guide. We'll review it before you release your app. -* **App store description**: +### Every app and theme based on the app system - * The mandatory number of characters is set in short and long descriptions. No blank spaces as fillers are allowed (EN/DE). - * Check if the description makes sense and if it includes step-by-step instructions on how to use and test your app. - * Check if you have included enough screenshots showing the app in action in the Storefront and Administration (please add a screenshot of the app in the extension manager settings). - * Check if the display name does not contain the term "plugin." +* We pay attention to the automatic code review and look for security issues and shopware coding standards in the manual code review. -* We pay attention to the automatic code review and look for security issues. +* We check the complete functionality of the app (separately sales channel configurations in the config.xml, the uninstallation and reinstallation procedure) and check for styling errors on every viewport. -* **Cookie check in the browser console**: If the app sets cookies in any way in the checkout, these cookies must be registered to the cookie configuration box in the frontend. +* We want to improve the quality of the Shopware Community Store and offer as many different apps as possible. +Hence, we check for a functional comparison with other apps already in the Shopware Community store, in the Rise edition or above. +If an extension with the same function exists and it does not fit into one of our differentiator clusters, it can be rejected as it doesn't provide any added value. +If you would like more information, please write an email to [qa@shopware.com](mailto:qa@shopware.com). -* Every external link in the Administration or Storefront must be marked as *rel="noopener" AND target="_blank"*. +Link: [Differentiator cluster for Shopware extensions](/docs/resources/guidelines/testing/Differentiator-Clusters.html) +Link: [Documentation for Extension Partner](https://docs.shopware.com/en/account-en/extension-partner/extensions?category=account-en/extension-partner#how-can-i-request-a-preview) -* We check for styling errors on every viewport. +::: info +**Safe your app idea and get a preview in the store** +If you already have an idea and don't want it to be snatched away, ensure you get it by creating a preview in your account. +You can apply for this if you have maintained placeholder images for the store, meaningful use cases, highlight features, a description, and a release month without uploading any binary. +::: -* We check the complete functionality of the app (including the uninstallation and reinstallation procedure). +## App / Theme store description -* New XHR requests in the storefront must be accompanied by an `X-Robots-Tag` in the header request with the directive "noindex, nofollow." For further details, please refer to the [robots meta tag](https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag?hl=de#xrobotstag) article. +The release to the English store is standard. +As an app / theme will be released in both stores (German and International), the content must accurately translate 1:1 from English to German. -* The utilization of H-tags is not permissible, as these tags are reserved exclusively for content purposes. However, you may employ `<span class="h2">`, for instance. +* The mandatory number of characters is set in short and long descriptions. No blank spaces as fillers are allowed (EN/DE). +* Check if the description makes sense and describe the use cases of your app. +* Check if your configuration manual includes step-by-step instructions on how to configure and use your app. +* Check if you have included enough screenshots showing the app in action in the Storefront and administration. +* Check if the display name does not contain the terms "plugin" or "shopware". +* Check if all images for the English store description contain the English language. [Please do not mix English with other languages in your screenshots. Screenshots in German for the German store description are optional.] +* Check if you explained the setup of the app / theme and added a configuration manual. -* Compiled JavaScript offers many benefits such as improved performance and code optimization. However, it is difficult to read and understand the compiled code. -To ensure that the code remains accessible to all developers, the uncompiled version of the JavaScript code must be placed in a separate folder. This allows other developers to review and understand the code in its original, readable form. +### Display Name -* We want to improve the quality of the Shopware Community Store and offer as many different apps as possible. Hence, we check for a functional comparison with other apps already in the Shopware Community store, in the Rise edition, or above. If there is an app with the same function, it can be rejected as it doesn't provide any added value. For further information, write an email to [alliances@shopware.com](mailto:alliances@shopware.com). +According to the new naming scheme, extensions may no longer display the words "plugin" and "shopware" in their names. +An extension with a name that directly reflects its functional purpose is permissible, even if it shares the same name as another extension. -::: info -**Safe your app idea and get a preview in the store** - If you already have an idea and don't want it to be snatched away, then make sure you get it by creating a preview in your account. You can apply for this if you already have maintained images, description, and release months without uploading anything. -::: +Also, the store-display name had to be used for `theme.json` or `manifest.xml`. -### App descriptions in your Shopware account +### Short description -* **Display name:** According to the new naming scheme, the word "plugin" is no longer allowed in the display name of extensions. Instead of "Plugin" use "Extension" or "App". An extension with a name that directly reflects its functional purpose is permissible, even if it shares the same name as another extension. +(Min. 150 — max. 185 characters)—The app's short description must be unique and at least 150 characters long. +Use the short description wisely, as the text will tease your app in the overview along with the "Customers also bought" and "Customers also viewed" recommendations. +The short description is also published as a meta-description. -* **Short description:** (Min. 150 - max. 185 characters) - The app's short description must have at least 150 characters long and unique. Use the short description wisely, as the text will be used to tease your app in the overview along with the "Customers also bought" and "Customers also viewed" recommendations. The short description is also published as a meta-description. +### Description -* **Description:** (Min. 200 characters) - The app description must contain at least 200 characters and should clearly represent the app functions in detail. +(Min. 200 characters)—The app / theme description must be at least 200 characters long and describe the app's/theme's functions in detail. * Inline styles will be stripped. The following HTML tags are allowed: @@ -124,228 +104,338 @@ To ensure that the code remains accessible to all developers, the uncompiled ver * **Tips:** - * When it comes to increasing your app sales, it is important that potential customers feel completely informed about your products and services. To this end, you should provide a description that is meaningful, detailed, and easy to understand, even for people with very little technical knowledge. Explain step-by-step how your app works and how to use it to achieve the desired result. Of course, your app description should be accompanied by clean HTML source code. + * When it comes to increasing your app / theme sales, it is important that potential customers feel completely informed about your products and services. + To this end, you should provide description, highlights, and features that are meaningful, detailed, and easy to understand, even for people with very minimal technical knowledge. + Explain step-by-step how your app works and how to use it to achieve the desired result. + Of course, your app description should be accompanied by clean HTML source code. - * Video content increases awareness, trust and has proven to convert potential customers better than other content types. Help your customers better understand your app or service with explainer videos, product demos, tutorials, etc. You can embed maximum 2 YouTube videos in your app description. + * Video content increases awareness and trust and has proven to convert potential customers better than other content types. + You can help your customers better understand your app or service with explainer videos, product demos, tutorials, etc. + You can embed a maximum of 2 YouTube videos in your app description. ::: info -You can no longer advertise your Shopware certificates within the app description, in your app images, or in your manufacturer profile. The manufacturer/partner certificates are dynamically loaded at the end of each app description and published by us. + You can no longer advertise your Shopware certificates within the app description, in your app images, or in your manufacturer profile. The manufacturer/partner certificates are dynamically loaded at the end of each app description and published by us. ::: -* Include several screenshots and descriptive images from the Storefront and backend that represent the app functionality. They must show the app "in action", its configuration options, and how to use it. +### Images + +::: info +Screenshots and preview images in English are standard. Only full English screenshots are accepted. Please do not mix English with other languages in your screenshots. Screenshots in German for the German store description are optional. +::: -* Be sure that the app is assigned to the appropriate categories. +Include several screenshots and descriptive images from the Storefront and backend that represent the app functionality. +They must show the app "in action", its configuration options, and how to use it. +We recommend uploading screenshots showing the mobile and desktop-view. -* The link must be valid if you provide a demo shop (the URL cannot contain http: or https:). +[How To - Add images and icons to extensions](https://docs.shopware.com/en/account-en/adding-pictures-and-icons/how-to) -* The description must be a 1:1 translation. As an app is to be released in both stores (German and International), the content must be accurately translated 1:1 from/to German/English.​​​ +### Link to demoshop -* If necessary, personal data protection information has to be set. If personal data of the customers (store operator and/or his customers) are processed with this extension according to Art. 28 DSGVO, the following information of the data processing company must be stored in the field "Subprocessor". If other companies are involved in the data processing of personal data, the same information must be stored accordingly for them in the field "Further subprocessors". +If you provide a demo shop, the link must be valid (the URL cannot contain `http:` or `https:`). +Do not link to your test environments, as we will delete them automatically two weeks after they are created. -* Your manufacturer profile must mandatorily contain accurate English and German descriptions and a manufacturer logo. You can find the manufacturer profile in your account under Shopware Account > Extension Administration > Manufacturer profile. +### Personal data protection information -* The content of the images/screenshots must be in English. +If necessary, personal data protection information has to be set. +If personal data of the customers (store operator and/or his customers) are processed with this extension according to Art. 28 DSGVO, the following information of the data processing company must be stored in the field "Subprocessor". + +If other companies are involved in the data processing of personal data, the same information must be stored accordingly for them in the field "Further subprocessors". + +### Configuration manual + +Explain how your app is installed and configured, how it works on a technical base, and how it can be used to achieve the desired result. +Of course, your app manual should contain a setup guide and be accompanied by clean HTML source code. + +### Manufacturer Profile + +Your manufacturer profile must mandatorily contain accurate English and German descriptions and a manufacturer logo. +You can find the manufacturer profile in your account under Shopware Account > Extension Partner > [Extension Partner profile](https://account.shopware.com/producer/profile). ::: info -Iframes, external scripts, or tracking pixels are not allowed in the descriptions, profiles, and instructions of the source code. Custom styles may not overwrite the original Shopware styles. External sources must be included via https. +The source code's descriptions, profiles, and instructions do not allow iframes, external scripts, or tracking pixels. +Custom styles may not overwrite the original Shopware styles. External sources must be included via https. ::: -### Template tests +## Basic Guidelines -* **Testing tools**: +### Testing functionality +Due to our quality assurance, we check the app's / theme's complete functionality and test it wherever it impacts the administration or storefront. - * [Schema Markup Validator of Schema.org](https://validator.schema.org/) +Also, every app / theme will be code-reviewed by one of our core-developer ensuring coding and security standards. - * [Google Lighthouse](https://developers.google.com/web/tools/lighthouse) +### Extension master data/license -### Theme apps +Please enter the valid license you set in your Shopware account. +You have to identify this license in the `manifest.xml` as well. -* There must be a preview image available in the *Theme Manager*. +::: info +The chosen license can't be changed after adding your app / theme to your account. +If you want to change the license later, add a new app based on the app system with a new technical name and upload the extension again. +::: -* Links must include a "title-tag" and images must have an "alt-tag". +### Fallback language / Translations -* Use *Scheme.org's Structured Data Testing Tool* to check the homepage, categories, and various product detail pages (incl. available products, unavailable products, products with no review, single review, many reviews with various ratings, out of stock products, products to be released in the future or any other kind of product configuration). Also, check for any new bugs. +The installation is not always in English or German. +Could you make sure that your app works in other languages as well? +For example, if the customer has his installation in Spanish and your app is not yet available in this language, you should use the English translation as a fallback. Our test environment includes Dutch as the standard language. -* Do a *Lighthouse Audit* to check the performance and quality of your frontend app. There should not be any drastic change in performance or accessibility values when activating the app. +If your app is available in more than one language (e.g., English, Spanish, French and German), these can be defined using the option "Translations into the following languages are available" (located in the “Description & images” section of your *Extension Manager*). -* The price and shopping cart button may not be covered by customizations - for example, "badges". Furthermore, the shopping cart button must always be clickable. +We check for text snippets, `config.xml`, `manifest.xml`, or `theme.json`. -### Service Solution App (SSA) +### Valid preview images for the Shopware administration -With SSA, you can offer API services for apps in the store. We recommend you develop this as a cloud app. The app will be available for both cloud and on-premises customers. The following basic requirements must be met: +Preview images: There must be a preview image available in the *Extension Manager*. +You must upload a valid favicon named plugin.png (png / 40 x 40 px) for the app. +This favicon will help you identify your app in the Extension Manager module in the administration. +The favicon has to be stored under `src/Resources/config/`. -* The manufacturer contract must be accepted. +Also, provide a preview image for Themes in the *Theme Manager* and CMS elements in the *Shopping Experiences*. -* The STP (Shopware technology partner) contract must be additionally concluded with the technology. +### Configuration per sales channel -* Add the company logo and the manifest file. For more support, refer to our [App Base Guide](/docs/guides/plugins/apps/app-base-guide). +Apps that appear in the Storefront and use a `config.xml` must be able to be configured separately for each sales channel. -::: warning -The name of your app that you provide in the manifest file needs to match the folder name of your app. -::: +### External links with rel="noopener" -* Upload your app to your Account. +Every external link in the administration or Storefront must be marked as *rel="noopener" AND target="_blank"*. -* Submit your app for automatic and manual code review. +### Error messages and logging -* Launch your successfully tested app in our store. +Error or informational messages can only be recorded in the event log of Shopware's log folder (/var/log/). +You have to develop your own log service. +Never write app exceptions into the Shopware default log or outside the Shopware system log folder. +This ensures that the log file can never be accessed via the URL. -### Shopping worlds/storytelling elements +### Avoid 400/500 Error -* Links must include a "title-tag" and images must have an "alt-tag". +*Avoid 500 errors at any time.* Avoid 400 errors unless they are related to an API call. -* Test the frontend and the checkout with the Debug Console – also pay attention to new JavaScript errors. +### Not allowed to extend the Extension Manager -* Use *Scheme.org's Structured Data Testing Tool* to check the homepage, categories, and various product detail pages (incl. available products, unavailable products, products with no review, single review, many reviews with various ratings, out of stock products, products to be released in the future or any other kind of product configuration). Also, check for any new bugs. +The *Extension Manager* must not be extended or overwritten. -* Do a *Lighthouse Audit* to check the performance and quality of your frontend app. There should not be any drastic change in performance or accessibility values when activating the app. +### Extension manager -### Frontend apps +The Debug Console controls the app's installation, uninstallation, reinstallation, and deletion. +No 400 errors or exceptions are allowed to appear. If the app requires special PHP options, it must be queried during installation. +If the query is negative, a growl message must appear in the administration. -* Links must include a "title-tag" and images must have an "alt-tag". +### Reloading of files not allowed -* If you create custom controller URLs in the sales channel, please note that we check for SEO and a valid canonical-tag. +Apps / Themes may not load other files during and after the installation in the *Extension Manager*. -* Use *Scheme.org's Structured Data Testing Tool* to check the homepage, categories, and various product detail pages (incl. available products, unavailable products, products with no review, single review, many reviews with various ratings, out of stock products, products to be released in the future or any other kind of product configuration). Also, check for any new bugs. +### Uncompiled JavaScript must be delivered within the binary -* We check for new errors throughout the entire Storefront using the Browser Debug Console. We also pay attention to new JavaScript errors. +Compiled JavaScript offers many benefits such as improved performance and code optimization. +However, it is difficult to read and understand the compiled code. +The uncompiled JavaScript code must be placed in a separate folder to ensure it remains accessible to all developers. +This allows other developers to review and understand the code in its original, readable form. -* We do a *Lighthouse Audit* to check the performance and quality of your frontend app. There should not be any drastic change in performance or accessibility values when activating the app. +Please build your `main.js` as described in our documentation and create the minified code as described in our developer documentation. -### Admin apps +Link: [Loading the JS files](/docs/guides/plugins/plugins/administration/add-custom-field.html#loading-the-js-files) +Link: [Injecting into the Administration](/docs/guides/plugins/plugins/administration/add-custom-field.html#injecting-into-the-administration) -We check the complete functionality of the app and test wherever the Administration is impacted by the app. +Shopware reserves the right to publish extensions with minified code after individual consideration and consultation with the developer. +For this, the developer must ensure that Shopware has access to the current unminified code of the extension at all times. -### API or payment apps +### Message queue -* The functionality of an app will be tested together with the app developer in a live session. +If the extension adds messages to the message queue, ensure they are not bigger than 262,144 bytes (256 KB). +This limitation is set by common message queue workers and should not be exceeded. -* Define in the description which currencies/countries are compatible with the payment method. +### Note on Shopware technology partner contract for interfaces -### External technology/ Shopware Technology Partner (STP) apps +You have now read the complete list of requirements for developing and releasing apps based on our app system in the Shopware Community Store. -Every external technology app needs to track its commission. Below is an example of implementing the tracking logic in their extensions: +If your app is a software app/interface with downstream costs, transaction fees, or service fees for the customer, we need to complete a technology partner agreement in order to activate your app. -// POST /shopwarepartners/reports/technology - Allows partners to send us the info based on the STP contract +If you have any questions regarding the technology partner agreement, please contact our sales team by writing an email to [alliances@shopware.com](mailto:alliances@shopware.com) or calling **+44 (0) 203 095 2445 (UK) / 00 800 746 7626 0 (worldwide) / +49 (0) 25 55 / 928 85-0 (Germany)**. -```json - { - "identifier": "8e167662-6bbb-11eb-9439-0242ac130002", - "reportDate": "2005-08-15T15:52:01", - "instanceId": "alur24esfaw3ghk", - "shopwareVersion": "6.3.1", - "reportDataKeys": [ - { - "customer": 3 - }, - { - "turnover": 440 - } - ] - } -``` +## Storefront Guidelines -## Quality guidelines for Shopware 6 apps based on the app system +### Testing the storefront -### Extension master data/license +Test the frontend and the checkout for new errors throughout the entire Storefront using the Browser Debug Console and also pay attention to JavaScript errors. -Please enter the valid license you set in your Shopware account. You have to identify this license in the manifest.xml as well. +### Links must include a title tag -::: info -The chosen license can't be changed after adding your app to your account. If you want to change the license later, you must add a new app based on the app system with a new technical name and upload the extension again. -::: +Links in the storefront and administration must include a meaningful "title tag". -### Fallback language +### Images must include the alt-tag -The installation is not always in English or German. So make sure that your app works in other languages as well. For example, if the customer has the installation in Spanish and your app is not yet available in this language, you should use the English translation as a fallback. Our test environment includes Dutch as the standard language. +Links in the storefront and administration must include a meaningful "alt tag" or the original alt tag from the media manager. -### Translations +### Do not use `<hX>`-Tags -If your app is available in more than one language (e.g., English and German), these can be defined using the option "Translations into the following languages are available" (located in the “Description & images” section of your *Extension Manager*). +The utilization of `<hX>`-tags in the storefront templates, which are set to `<meta name="robots" content="index,follow">`, is not permissible, as these tags are reserved exclusively for content purposes. +However, you may employ `<span class="h2">`, for instance. -### Valid app favicon for the Shopware Administration +### Do not use inline-css in the storefront templates -You must upload a valid favicon named plugin.png (png / 40 x 40 px) for the app. This favicon will make it easier to identify your app in the *Extension Manager* module in the backend. The favicon has to be stored under `src/Resources/config/`. +Use your own classes and let your CSS be compiled by the theme. -### Error messages must be entered in the event log +### New controller URLs / XHR requests -Error or informational messages can only be recorded in the event log of Shopware's log folder (/var/log/). You have to develop your own app-specific logger. Never write app exceptions into the Shopware default log or outside the Shopware system's log folder. This ensures that the log file can never be accessed via URL. +We check for new XHR/Document requests in the storefront as they must be accompanied by an `X-Robots-Tag` in the header request with the directive "noindex, nofollow.". +For further details, please refer to the [robots meta tag](https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag?hl=de#xrobotstag) article. -::: danger -Avoid 400/500 errors at any time unless the 400 errors are related to an API call. -::: +If the app creates its own controller URLs set to "index, follow" and the URLs are accessible via the frontend, then these "app URLs" must also appear in the `sitemap.xml`. +In addition, these pages must include a valid canonical tag, their own meta description, and a title tag, which can be entered individually via the administration or as a text snippet. -### Extension manager +### Lighthouse A/B-Testing: -The Debug Console controls the app's installation, uninstallation, reinstallation, and deletion. No 400 errors or exceptions are allowed to appear. +Could you do an A/B test with *Lighthouse Audit* to check the performance and quality of your frontend app? +There should not be any drastic change in performance, accessibility values, or any new errors when activating the app. -### Reloading of files not allowed +* **Testing tool** for A/B-Testing: + * [Google Lighthouse](https://developers.google.com/web/tools/lighthouse) -Apps may not load other files during and after the installation in the *Extension Manager*. +### schema.org/Rich Snippets A/B-Testing: -### App pages with their own URL must appear in the sitemap.xml +Do an A/B-Test with *Scheme.org's Structured Data Testing Tool* and *Google Rich Result Tester* to check the homepage, categories, and various product detail pages (incl. available products, unavailable products, products with no review, single review, many reviews with various ratings, out-of-stock products, products to be released in the future or any other kind of product configuration and products including ean, mpn, width, length, height, weight). +Also, could you check for duplicate entries as well as any new bugs? -If the app creates its own pages that are set to "index, follow" and the URLs are accessible via the frontend, then these "app URLs" must also appear in the `sitemap.xml`. In addition, these pages must include their own "meta description" and "title-tag", which can be entered individually via the backend or as a text snippet. +* **Testing tool** for A/B-Testing: + * [Schema Markup Validator of schema.org](https://validator.schema.org/) + * [Google Rich Result Tester] (https://search.google.com/test/rich-results) -### Register a cookie to the Cookie Consent Manager +### Usage of fonts from external sources -We expect that every cookie set from the store URL is [registered in our Cookie Consent Manager](/docs/guides/plugins/plugins/storefront/add-cookie-to-manager). We differentiate between "Technically required", "Comfort functions" and "Statistics and Tracking". All cookies have to appear in the cookie configuration box in the frontend. +If you are using external fonts (e.g., Google fonts, Fontawesome) or external services, the app store description must contain this information. -### Shopping worlds/shopping experiences +Please be aware that you might have to edit your *data protection information*. +This info could be placed as a tooltip near the font settings of the app configuration. -[Shopping worlds elements](#shopping-worldsstorytelling-elements) element must include an element icon. If the app is deleted, *Shopping worlds* should continue to work flawlessly in the frontend. +### Register your cookie to the Cookie Consent Manager -### Menu entries in the main menu not allowed +We expect every cookie set from the store URL to be optional and not technically required for running shopware. +Therefore, the cookies had to be [registered in our Cookie Consent Manager](/docs/guides/plugins/apps/storefront/cookies-with-apps.html). -Menu entries in the main menu of the Administration are not allowed because of the look and feel. +We differentiate between "Technically required", ,"Marketing" and "Comfort features". +All cookies must appear (unchecked) in the cookie configuration box in the frontend. -### Automated code tests with Cypress +## Administration guidelines -There are Cypress tests for Shopware 6 on GitHub. The project is driven by the *Friends of Shopware* group. You can contribute at any time: +### Menu entries in the main menu are not allowed -* [Developer Documentation Cypress Tests for Shopware 6](/docs/guides/plugins/plugins/testing/end-to-end-testing) -* [Cypress Tests for Shopware 6](https://github.com/shopware/shopware/tree/trunk/src/Administration/Resources) +Menu entries in the main menu of the administration are not allowed because of the look and feel. -### Helpful tools for app developers +### Own media folder -* [FroshPluginUploader](https://github.com/FriendsOfShopware/FroshPluginUploader): Tool for validating and uploading new SW6 app releases to the Community Store (GitHub Project from "Friends of Shopware")] -* [Shopware CLI tools](https://github.com/shopwareLabs/sw-cli-tools): When you think about performance, these are various useful console helpers for generating data. +Customers must create their own media folders with the right thumbnail settings or use existing ones to upload images. -### Descriptions in your Shopware account +If you use your own media folder, keep in mind that the folder and the included data had to be removed if selected during the uninstallation. -[App descriptions in your Shopware account](#app-descriptions-in-your-shopware-account) must follow the checklist criterion. +### Shopping experiences -## Automatic code review - Errors +[Shopping worlds elements](/docs/concepts/commerce/content/shopping-experiences-cms.html#elements) must include an element icon. +If the app is deleted, *Shopping Worlds* should work flawlessly in the frontend. -### Ensure cross-domain messages are sent to the intended domain +### Themes -See ["Cross-document messaging domains should be carefully restricted"](https://rules.sonarsource.com/javascript/RSPEC-2819) for more information. +[Themes](/docs/guides/plugins/themes/) must include its own preview image. -### No bootstrapping file found. Expecting bootstrapping in +### External technology/ Shopware Technology Partner (STP) apps -The bootstrap cannot be found. The reasons could be that the folder structure in the ZIP file is incorrect, there could be a typo, or a case-sensitive error in the app source (e.g., in the technical name). +Every external technology app needs to track its commission. +Below is an example of implementing the tracking logic in their extensions: -### Cookies are written safely +// POST /shopwarepartners/reports/technology - Allows partners to send us the info based on the STP contract + +```json + { + "identifier": "8e167662-6bbb-11eb-9439-0242ac130002", + "reportDate": "2005-08-15T15:52:01", + "instanceId": "alur24esfaw3ghk", + "shopwareVersion": "6.3.1", + "reportDataKeys": [ + { + "customer": 3 + }, + { + "turnover": 440 + } + ] + } +``` -Be sure you set cookies as secure. Remember to register your cookie to the *Cookie Consent Manager*. +### Automatic code reviews with PhpStan and SonarQube -### Unauthorized file formats or folders detected in the app. Please remove the following files/folders +Our most current code review configurations when uploading apps via the Shopware Account can be found on GitHub. -Not allowed folders and files: +* Link: [Code reviews for Shopware 6 on GitHub](https://github.com/shopwareLabs/store-plugin-codereview) - * .gitignore - * .DS_Store - * Thumbs.db - * .git, __MACOSX - * .zip - * .tar - * .tar.gz - * .phar +### Sonarcube Rules status Blocker -## Note on Shopware technology partner contract for interfaces +The following statements will be blocked as of 1st Oct. 2022: +-die; exit; var_dump -You have now read the complete list of requirements for developing and releasing apps based on our app system in the Shopware Community Store. +[Refer to the list of the already existing blockers](https://s3.eu-central-1.amazonaws.com/wiki-assets.shopware.com/1657519735/blocker.txt). -If your app is a software app/interface with downstream costs, transaction fees, or service fees for the customer, we need to complete a technology partner agreement in order to activate your apps. +### Helpful tools for app developers +* [FroshPluginUploader](https://github.com/FriendsOfShopware/FroshPluginUploader): Tool for validating and uploading new SW6 app releases to the Community Store (GitHub Project from "Friends of Shopware")] +* [Shopware CLI tools](https://github.com/shopwareLabs/sw-cli-tools): When you think about performance, these are various useful console helpers for generating data. -If you have any questions regarding the technology partner agreement, please contact our sales team by writing an email to [alliances@shopware.com](mailto:alliances@shopware.com) or calling **+44 (0) 203 095 2445 (UK) / 00 800 746 7626 0 (worldwide) / +49 (0) 25 55 / 928 85-0 (Germany)**. +## Automatic code review - Errors + +### The required manifest.xml file was not found + +**Cause:** Error in manifest.xml + +One possible cause is that the technical app name from the Community Store or Account does not match the technical name entered in manifest.xml, or the app is incorrectly zipped. +The technical app name must be stored in the first part of manifest.xml. +Most of the errors are caused by the wrong technical name. +For example, "Swag\\MyPlugin\\SwagMyPluginSW6" instead of "Swag\\MyPlugin\\SwagMyPlugin". + +[Here is an example](https://developer.shopware.com/docs/resources/references/app-reference/manifest-reference.html#manifest-reference) of a valid manifest.xml. + +### Ensure cross-domain messages are sent to the intended domain + +See ["Cross-document messaging domains should be carefully restricted"](https://rules.sonarsource.com/javascript/RSPEC-2819) for more information. + +### Class Shopware\Storefront\* not found + +Missing requirements in the theme.json (e.g. "require": {"shopware/frontend": "*"},) +See "[Shopware App Development: App Meta Information - Explanation of the properties](../../../../../guides/plugins/plugins/plugin-base-guide#the-composerjson-file) for more information. + +### Cookies are written safely + +Be sure you set cookies as secure. +Remember to register your cookie to the *Cookie Consent Manager*. + +### The lock file is not up to date with the latest changes in manifest.xml. +You may need to get updated dependencies. Run an update to update them. + +The `composer.lock` in the app archive has to be deleted. + +### Remove out-commented code from your source-code + +### Unauthorized file formats or folders detected in the app. + +Remove out-commented code, unused files and folders, and all dev-files from your binary. + +Here are some examples of not allowed folders and files: +* /__MACOSX +*./tests +* .gitignore +* .gitkeep +* .gitlab-ci.yml +* .DS_Store +* .editorconfig +* .git +* .gitignore +* .phar +* .prettierrc +* .shopware-extension.yml +* .tar +* .tar.gz +* .zip +* composer.lock +* package.json +* package-lock.json +* phpunitx.xml +* shell.nix +* Thumbs.db +* webpack.config.js diff --git a/resources/guidelines/testing/store/quality-guidelines-plugins/index.md b/resources/guidelines/testing/store/quality-guidelines-plugins/index.md index 8953f8769..9e570e8d8 100644 --- a/resources/guidelines/testing/store/quality-guidelines-plugins/index.md +++ b/resources/guidelines/testing/store/quality-guidelines-plugins/index.md @@ -1,6 +1,6 @@ --- nav: - title: Quality guidelines for apps in plugin system + title: Quality guidelines for apps in the plugin system position: 10 --- @@ -8,134 +8,93 @@ nav: # Quality Guidelines for the Plugin System in the Shopware Store > **Changelog** ->> 01/08/24: [Added - Message queue](../quality-guidelines-plugins/#message-queue) > ->> 26/07/23: [Added - Identical name rule](../quality-guidelines-plugins/#every-app-based-on-the-plugin-system) -> ->> 06/09/23: [Added - Rules for own composer dependencies](../quality-guidelines-plugins/#own-composer-dependencies) -> ->> 26/07/23: [Added - Name preset according to new naming scheme](../quality-guidelines-plugins/#every-app-based-on-the-plugin-system) -> ->> 18/07/23: [Compiled code](../quality-guidelines-plugins/#checklist-for-app-testing) -> ->> 12/04/23: [Check for a functional comparison with functions from the Rise or above edition.](../quality-guidelines-plugins/#every-app-based-on-the-plugin-system) -> ->> 14/02/23: [Added new STP tracking - External technology apps/STP apps.](../quality-guidelines-plugins/#external-technology-shopware-technology-partner-stp-apps) -> ->> 11/07/22: [Added a list of all Blockers - Changes to the autom. codereview 1.st Oct. 2022](../quality-guidelines-plugins/#sonarcube-rules-status-blocker) -> ->> 26/10/21: [Added safe your app idea and get a preview in the store.](../quality-guidelines-plugins/#every-app-based-on-the-plugin-system) +>> 09/10/24: Quality guidelines for apps in the plugin system. > ->> 14/10/21: [How we test your extension for the Shopware Store (DE).](https://www.youtube.com/watch?v=gLb5CmOdi4g) +>> 01/08/24: [Added - Message queue](..//quality-guidelines-plugins/#message-queue) > ->> 08/06/21: [Added URL and info regarding our docker environment we use for testing SW6 apps.](../quality-guidelines-plugins/#the-way-we-test-apps-based-on-the-plugin-system) -> ->> 07/06/21: [Template Tests - Now using Scheme.org Structured Data Testing Tool instead of Google Structured Testing Tool.](../quality-guidelines-plugins/#template-tests) -> ->> 07/06/21: [Account app description - Subprocessor and/or Further subprocessors information may be required for your app.](../quality-guidelines-plugins/#app-descriptions-in-your-shopware-account) -> ->> 17/04/21: Restructured the quality guidelines. No new content added. -> ->> 12/05/20: [Added app Checklist for your Quality assurance.](../quality-guidelines-plugins/#checklist-for-app-testing) +>> 06/09/23: [Added - Rules for own composer dependencies](../quality-guidelines-plugins/#own-composer-dependencies) > ->> 22/04/20: [Menu entries in the main menu of the Administration are not allowed anymore because of the look and feel.](../quality-guidelines-plugins/#menu-entries-in-the-main-menu-not-allowed) +>> 26/07/23: [Added - Identical name rule](../quality-guidelines-plugins/#every-app-based-on-the-plugin-system) ## The way we test apps based on the plugin system -It is always a good idea to review the process of how we conduct tests prior to submitting your app for review. +It is always a good idea to review our test process before submitting your app for review. This ensures the quickest way for your app to be published. We perform the *first test*, and if successful, we do the *follow-up test* again with the most current Shopware version. The Shopware installation is located in a subfolder. It has a language sub-shop/sales channel with a virtual URL as well as an independent sub-shop/sales channel with its own URL, also located in a subfolder. -E.g. `myshop.com/subfolder/backend` or `myshop.com/public/admin`. -The app must neither produce any error messages in the backend nor in the frontend. +E.g. `myshop.com/public/admin`. +The app must neither produce any error messages in the administration nor in the frontend. The app is tested with the latest official Shopware 6 CE Version. -Our testing environment is built with the following components: Nginx Webserver, PHP 7.4 as FPM, MariaDB latest, Shopware installed in subfolder `/shop/public`, default Shopware language Dutch. -The environment is built using Docker and is published on Docker Hub. You can use the following command to run it on your system: - -```markdown -docker run --rm -p 80:80 -e VIRTUAL_HOST=localhost ghcr.io/shopwarelabs/testenv:6.X.X -``` - -::: info -The shop will be accessible at `http://localhost/shop/public` -Admin-User: demo -Admin-Password: demodemo -::: ::: info We always test with the [actual SW6 version](https://www.shopware.com/de/download/#shopware-6). -So set it to the actual SW6 version e.g., ghcr.io/shopwarelabs/testenv:6.4.3. +So set it to the actual SW6 version e.g., shopware/testenv:6.6.6. Always test with the app`s highest supported Shopware version. ::: -[Test your extension for the Shopware Store (DE):](https://www.youtube.com/watch?v=gLb5CmOdi4g) and EN version is coming soon. +[Test your app for the Shopware Store (DE):](https://www.youtube.com/watch?v=gLb5CmOdi4g) and EN version is coming soon. -**Progressive Web App:** If your app is PWA compatible, and you would like the PWA flag, please contact us at [alliances@shopware.com](mailto:alliances@shopware.com). +**Progressive Web App:** If your app is PWA compatible and you would like the PWA flag, please contact us at [alliances@shopware.com](mailto:alliances@shopware.com). ## Checklist for app testing -Be sure to use the most recent testing checklist from Shopware and not from any other provider. -Please pay attention to every single point in this guide, as this will be reviewed by us in order to release your app. +Could you be sure to use the most recent testing checklist from Shopware and not any other provider? +Please pay attention to every point in this guide. We'll review it before you release your app. ### Every app based on the plugin system -* If you are using external fonts (e.g., from Google fonts) or external services, the app store description must contain this information. -Please be aware that you might have to edit your *data protection information*. -This info could be otherwise placed as a tooltip near the font settings of the app configuration. +* We pay attention to the automatic code review and look for security issues and shopware coding standards in the manual code review. -* **App store description**: - * The mandatory number of characters is set in short and long descriptions. No blank spaces as fillers are allowed (EN/DE). - * Check if the description makes sense and if it includes step-by-step instructions on how to use and test your app. - * Check if you have included enough screenshots showing the app in action in the Storefront and Administration (please add a screenshot of the app in the extension manager settings). - * Check if the display name does not contain the term "plugin." +* We check the complete functionality of the app (separately sales channel configurations in the config.xml, the uninstallation and reinstallation procedure) and check for styling errors on every viewport. -* We pay attention to the automatic code review and look for security issues. +* We want to improve the quality of the Shopware Community Store and offer as many different apps as possible. +Hence, we check for a functional comparison with other apps already in the Shopware Community store, in the Rise edition or above. +If an extension with the same function exists and it does not fit into one of our differentiator clusters, it can be rejected as it doesn't provide any added value. +If you would like more information, please write an email to [qa@shopware.com](mailto:qa@shopware.com). -* **Cookie check in the browser console**: If the app sets cookies in any way in the checkout, these cookies must be registered to the cookie configuration box in the frontend. +[Differentiator cluster for Shopware extensions](https://developer.shopware.com/docs/resources/guidelines/testing/Differentiator-Clusters.html) +[Documentation for Extension Partner](https://docs.shopware.com/en/account-en/extension-partner/extensions?category=account-en/extension-partner#how-can-i-request-a-preview) -* Every external link in the Administration or Storefront must be marked as *rel="noopener" AND target="_blank"*. +::: info +**Safe your app idea and get a preview in the store** +If you already have an idea and don't want it to be snatched away, ensure you get it by creating a preview in your account. +You can apply for this if you have maintained placeholder images for the store, meaningful use cases, highlight features, a description, and a release month without uploading any binary. +::: -* We check for styling errors on every viewport. +## App store description -* We check the complete functionality of the app (including the uninstallation and reinstallation procedure). +The release to the English store is standard. +As an app will be released in both stores (German and International), the content must accurately translate 1:1 from English to German. -* New XHR requests in the storefront must be accompanied by an `X-Robots-Tag` in the header request with the directive "noindex, nofollow." -For further details, please refer to the [robots meta tag](https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag?hl=de#xrobotstag) article. +* The mandatory number of characters is set in short and long descriptions. No blank spaces as fillers are allowed (EN/DE). +* Check if the description makes sense and describe the use cases of your app. +* Check if your configuration manual includes step-by-step instructions on how to configure and use your app. +* Check if you have included enough screenshots showing the app in action in the Storefront and administration. +* Check if the display name does not contain the terms "plugin" or "shopware". +* Check if all images for the English store description contain the English language. [Please do not mix English with other languages in your screenshots. Screenshots in German for the German store description are optional.] +* Check if you explained the setup of the app and added a configuration manual. -* The utilization of H-tags is not permissible, as these tags are reserved exclusively for content purposes. -However, you may employ `<span class="h2">`, for instance. +### Display Name -* Compiled JavaScript offers many benefits such as improved performance and code optimization. -However, it is difficult to read and understand the compiled code. -To ensure that the code remains accessible to all developers, the uncompiled version of the JavaScript code must be placed in a separate folder. -This allows other developers to review and understand the code in its original, readable form. -Shopware reserves the right to publish extensions with minified code after individual consideration and consultation with the developer. For this, the developer must ensure that Shopware has access to the current unminified code of the extension at all times. - -* We want to improve the quality of the Shopware Community Store and offer as many different apps as possible. -Hence, we check for a functional comparison with other apps already in the Shopware Community store, in the Rise edition, or above. -If there is an app with the same function, it can be rejected as it doesn't provide any added value. -For further information, write an email to [alliances@shopware.com](mailto:alliances@shopware.com). - -::: info -**Safe your app idea and get a preview in the store** - If you already have an idea and don't want it to be snatched away, then make sure you get it by creating a preview in your account. -You can apply for this if you already have maintained images, description, and release months without uploading anything. -::: +According to the new naming scheme, extensions may no longer display the words "plugin" and "shopware" in their names. +An extension with a name that directly reflects its functional purpose is permissible, even if it shares the same name as another extension. -### App descriptions in your Shopware account +Also, the store-display name had to be used for `composer.json` and `config.xml`. -* **Display name:** According to the new naming scheme, the word "plugin" is no longer allowed in the display name of extensions. -Instead of "Plugin" use "Extension" or "App". -An extension with a name that directly reflects its functional purpose is permissible, even if it shares the same name as another extension. +### Short description -* **Short description:** (Min. 150 - max. 185 characters) - The app's short description must have at least 150 characters long and unique. -Use the short description wisely, as the text will be used to tease your app in the overview along with the "Customers also bought" and "Customers also viewed" recommendations. +(Min. 150 — max. 185 characters)—The app's short description must be unique and at least 150 characters long. +Use the short description wisely, as the text will tease your app in the overview along with the "Customers also bought" and "Customers also viewed" recommendations. The short description is also published as a meta-description. -* **Description:** (Min. 200 characters) - The app description must contain at least 200 characters and should clearly represent the app functions in detail. +### Description + +(Min. 200 characters)—The app description must be at least 200 characters long and describe the app's functions in detail. * Inline styles will be stripped. The following HTML tags are allowed: @@ -143,154 +102,127 @@ The short description is also published as a meta-description. <a> <p> <br> <b> <strong> <i> <ul> <ol> <li> <h2> <h3> <h4> <h5> ``` -* **Tips:** - * When it comes to increasing your app sales, it is important that potential customers feel completely informed about your products and services. - To this end, you should provide a description that is meaningful, detailed, and easy to understand, even for people with very little technical knowledge. - Explain step-by-step how your app works and how to use it to achieve the desired result. - Of course, your app description should be accompanied by clean HTML source code. - * Video content increases awareness, trust and has proven to convert potential customers better than other content types. - Help your customers better understand your app or service with explainer videos, product demos, tutorials, etc. - You can embed maximum 2 YouTube videos in your app description. - -::: info -You can no longer advertise your Shopware certificates within the app description, in your app images, or in your manufacturer profile. The manufacturer/partner certificates are dynamically loaded at the end of each app description and published by us. -::: - -* Include several screenshots and descriptive images from the Storefront and backend that represent the app functionality. -They must show the app "in action", its configuration options, and how to use it. - -* Be sure that the app is assigned to the appropriate categories. - -* The link must be valid if you provide a demo shop (the URL cannot contain http: or https:). + * **Tips:** -* The description must be a 1:1 translation. -As an app is to be released in both stores (German and International), the content must be accurately translated 1:1 from/to German/English. + * When it comes to increasing your app sales, it is important that potential customers feel completely informed about your products and services. + To this end, you should provide description, highlights, and features that are meaningful, detailed, and easy to understand, even for people with very minimal technical knowledge. + Explain step-by-step how your app works and how to use it to achieve the desired result. + Of course, your app description should be accompanied by clean HTML source code. -* If necessary, personal data protection information has to be set. -If personal data of the customers (store operator and/or his customers) are processed with this extension according to Art. 28 DSGVO, the following information of the data processing company must be stored in the field "Subprocessor". -If other companies are involved in the data processing of personal data, the same information must be stored accordingly for them in the field "Further subprocessors". - -* Your manufacturer profile must mandatorily contain accurate English and German descriptions and a manufacturer logo. -You can find the manufacturer profile in your account under Shopware Account > Extension Administration > Manufacturer profile. - -* The content of the images/screenshots must be in English. + * Video content increases awareness and trust and has proven to convert potential customers better than other content types. + You can help your customers better understand your app or service with explainer videos, product demos, tutorials, etc. + You can embed a maximum of 2 YouTube videos in your app description. ::: info -Iframes, external scripts, or tracking pixels are not allowed in the descriptions, profiles, and instructions of the source code. -Custom styles may not overwrite the original Shopware styles. -External sources must be included via https. +You can no longer advertise your Shopware certificates within the app description, in your app images, or in your manufacturer profile. +The manufacturer/partner certificates are dynamically loaded at the end of each app description and published by us. ::: -### Template tests - -* **Testing tools**: - * [Schema Markup Validator of schema.org](https://validator.schema.org/) - * [Google Lighthouse](https://developers.google.com/web/tools/lighthouse) - -### Theme apps - -* There must be a preview image available in the *Theme Manager*. +### Images -* Links must include a "title-tag" and images must have an "alt-tag". - -* Use *Scheme.org's Structured Data Testing Tool* to check the homepage, categories, and various product detail pages -(incl. available products, unavailable products, products with no review, single review, many reviews with various ratings, out of stock products, products to be released in the future or any other kind of product configuration). -Also, check for any new bugs. - -* Do a *Lighthouse Audit* to check the performance and quality of your frontend app. -There should not be any drastic change in performance or accessibility values when activating the app. - -* The price and shopping cart button may not be covered by customizations - for example, "badges". -Furthermore, the shopping cart button must always be clickable. - -### Shopping worlds/storytelling elements - -* Links must include a "title-tag" and images must have an "alt-tag". +::: info +Screenshots and preview images in English are standard. Only full English screenshots are accepted. Please do not mix English with other languages in your screenshots. Screenshots in German for the German store description are optional. +::: -* Test the frontend and the checkout with the Debug Console – also pay attention to new JavaScript errors. +Include several screenshots and descriptive images from the Storefront and backend that represent the app functionality. +They must show the app "in action", its configuration options, and how to use it. +We recommend uploading screenshots showing the mobile and desktop-view. -* Use *Scheme.org's Structured Data Testing Tool* to check the homepage, categories, and various product detail pages -(incl. available products, unavailable products, products with no review, single review, many reviews with various ratings, out of stock products, products to be released in the future or any other kind of product configuration). -Also, check for any new bugs. +Take a look at [How To - Add images and icons to extensions](https://docs.shopware.com/en/account-en/adding-pictures-and-icons/how-to) -* Do a *Lighthouse Audit* to check the performance and quality of your frontend app. -There should not be any drastic change in performance or accessibility values when activating the app. +### Link to demoshop -### Frontend apps +If you provide a demo shop, the link must be valid (the URL cannot contain `http:` or `https:`). +Do not link to your test environments, as we will delete them automatically two weeks after they are created. -* Links must include a "title-tag" and images must have an "alt-tag". +### Personal data protection information -* If you create custom controller URLs in the sales channel, please note that we check for SEO and a valid canonical-tag. +If necessary, personal data protection information has to be set. +If personal data of the customers (store operator and/or his customers) are processed with this extension according to Art. 28 DSGVO, the following information of the data processing company must be stored in the field "Subprocessor". -* Use *Scheme.org's Structured Data Testing Tool* to check the homepage, categories, and various product detail pages -(incl. available products, unavailable products, products with no review, single review, many reviews with various ratings, out of stock products, products to be released in the future or any other kind of product configuration). -Also, check for any new bugs. +If other companies are involved in the data processing of personal data, the same information must be stored accordingly for them in the field "Further subprocessors". -* We check for new errors throughout the entire Storefront using the Browser Debug Console. -We also pay attention to new JavaScript errors. +### Configuration manual -* We do a *Lighthouse Audit* to check the performance and quality of your frontend app. -There should not be any drastic change in performance or accessibility values when activating the app. +Explain how your app is installed and configured, how it works on a technical base, and how it can be used to achieve the desired result. +Of course, your app manual should contain a setup guide and be accompanied by clean HTML source code. -### Backend apps +### Manufacturer Profile -We check the complete functionality of the app and test wherever the Administration is impacted by the app. +Your manufacturer profile must mandatorily contain accurate English and German descriptions and a manufacturer logo. +You can find the manufacturer profile in your account under Shopware Account > Extension Partner > [Extension Partner profile](https://account.shopware.com/producer/profile). -### API or Payment apps +::: info +The source code's descriptions, profiles, and instructions do not allow iframes, external scripts, or tracking pixels. +Custom styles may not overwrite the original Shopware styles. External sources must be included via https. +::: -* We check for an API test button. -Apart from that, you can validate the required credentials while saving them in the app settings. -In this case, a status message must be displayed in the backend and Shopware log. +## Basic Guidelines -* The functionality of an app will be tested together with the app developer in a live session. +### Testing functionality +Due to our quality assurance, we check the app's complete functionality and test it wherever it impacts the administration or storefront. -## Quality Guidelines for Shopware 6 extensions based on the plugin System +Also, every app will be code-reviewed by one of our core-developer ensuring coding and security standards. ### Extension master data/license Please enter the valid license you set in your Shopware account. -You have to identify this license in the manifest.xml as well. +You have to identify this license in the `composer.json` as well. ::: info The chosen license can't be changed after adding your app to your account. -If you want to change the license later, you must add a new app based on the app system with a new technical name and upload the extension again. +If you want to change the license later, add a new app based on the app system with a new technical name and upload the extension again. ::: -### Fallback language +### Fallback language / Translations The installation is not always in English or German. -So make sure that your app works in other languages as well. -For example, if the customer has his installation in Spanish and your app is not yet available in this language, you should use the English translation as a fallback. -Our test environment includes Dutch as the standard language. +Could you make sure that your app works in other languages as well? +For example, if the customer has his installation in Spanish and your app is not yet available in this language, you should use the English translation as a fallback. Our test environment includes Dutch as the standard language. -### Translations +If your app is available in more than one language (e.g., English, Spanish, French and German), these can be defined using the option "Translations into the following languages are available" (located in the “Description & images” section of your *Extension Manager*). -If your app is available in more than one language (e.g., English and German), these can be defined using the option "Translations into the following languages are available" (located in the “Description & images” section of your *Extension Manager*). +We check for text snippets, `config.xml`, and `composer.json`. -### Valid app favicon for the Shopware Administration +### Valid preview images for the Shopware administration +Preview images: There must be a preview image available in the *Extension Manager*. You must upload a valid favicon named plugin.png (png / 40 x 40 px) for the app. -This favicon will make it easier to identify your app in the *Extension Manager* module in the backend. -The favicon has to be stored under `src/Resources/config/`. +This favicon will help you identify your app in the Extension Manager module in the administration. +The favicon has to be stored under `src/Resources/config/`. + +Also, provide a preview image for Themes in the *Theme Manager* and CMS elements in the *Shopping Experiences*. + +### Configuration per sales channel + +Apps that appear in the Storefront and use a `config.xml` must be able to be configured separately for each sales channel. + +### External links with rel="noopener" -### Error messages must be entered in the event log +Every external link in the administration or Storefront must be marked as *rel="noopener" AND target="_blank"*. + +### Error messages and logging Error or informational messages can only be recorded in the event log of Shopware's log folder (/var/log/). You have to develop your own log service. Never write app exceptions into the Shopware default log or outside the Shopware system log folder. This ensures that the log file can never be accessed via the URL. -::: danger -Avoid 400/500 errors at any time unless the 400 errors are related to an API call. -::: +For payment apps, we check if the "plugin logger" service is used for the debug/error.log and that logs are written in the directory /var/log/. Log files must be used in every circumstance. -### Own media folder +The log file had to be named like this: "MyExtension-Year-Month-Day.log" + +Another solution is to store them in the database. +Try to avoid using your own log tables. Otherwise, you have to implement a scheduled task that regularly empties your log table within the given time of max. 6 months. -Customers must create own media folders or use existing ones to upload images. +### Avoid 400/500 Error -### With "Install/Uninstall" the user must decide whether the data/tables are to be deleted or not +*Avoid 500 errors at any time.* Avoid 400 errors unless they are related to an API call. -When clicking on the "Install / Uninstall" option in the Extension Manager, the user must be presented with the options "completely delete" or "keep the app data, text snippets, and table adjustments". +### With "Install/Uninstall" the user must decide whether the data/table is to be deleted or not + +When clicking on the "Install / Uninstall" option in the Extension Manager, the user must be presented with the options "completely delete" or "keep the app data, text snippets, media folder including own media and table adjustments". +You can check this using the Adminer-App from *Friends of Shopware* in your provided test-environment. ### Not allowed to extend the Extension Manager @@ -298,8 +230,8 @@ The *Extension Manager* must not be extended or overwritten. ### Own composer dependencies -Composer dependencies are possible as long as they are in the `composer.json`. -With `executeComposerCommands() === true` in the plugin base class we provide a dynamic installation of the composer dependencies by default, so they don't have to be included. +Composer dependencies are possible if they are in the `composer.json`. +With `executeComposerCommands() === true` in the plugin base class, we provide a dynamic installation of the composer dependencies by default, so they don't have to be included. Everything that is delivered in code should be traceable either directly or via `composer.json`. [Developer documentation article to add private dependency](../../../../../guides/plugins/plugins/plugin-fundamentals/using-composer-dependencies) @@ -307,49 +239,134 @@ Everything that is delivered in code should be traceable either directly or via ### Extension manager The Debug Console controls the app's installation, uninstallation, reinstallation, and deletion. -No 400 errors or exceptions are allowed to appear. -If the app requires special PHP options, it must be queried during installation. -If the query is negative, a growl message must appear in the backend. +No 400 errors or exceptions are allowed to appear. If the app requires special PHP options, it must be queried during installation. +If the query is negative, a growl message must appear in the administration. ### Reloading of files not allowed Apps may not load other files during and after the installation in the *Extension Manager*. +### Uncompiled JavaScript must be delivered within the binary + +Compiled JavaScript offers many benefits such as improved performance and code optimization. +However, it is difficult to read and understand the compiled code. +The uncompiled JavaScript code must be placed in a separate folder to ensure it remains accessible to all developers. +This allows other developers to review and understand the code in its original, readable form. + +Please build your `main.js` as described in our documentation and create the minified code as described in our developer documentation. + +[Loading the JS files](https://developer.shopware.com/docs/guides/plugins/plugins/administration/add-custom-field.html#loading-the-js-files) +[Injecting into the Administration](https://developer.shopware.com/docs/guides/plugins/plugins/administration/add-custom-field.html#injecting-into-the-administration) + +Shopware reserves the right to publish extensions with minified code after individual consideration and consultation with the developer. +For this, the developer must ensure that Shopware has access to the current unminified code of the extension at all times. + ### Message queue -If the extension adds messages to the message queue, make sure they are not bigger than 262,144 bytes (256 KB). +If the extension adds messages to the message queue, ensure they are not bigger than 262,144 bytes (256 KB). This limitation is set by common message queue workers and should not be exceeded. -### App pages with their own URL must appear in the sitemap.xml +### Note on Shopware technology partner contract for interfaces -If the app creates its own pages that are set to "index, follow" and the URLs are accessible via the frontend, then these "app URLs" must also appear in the sitemap.xml. -In addition, these pages must include their own "meta description" and "title-tag", which can be entered individually via the backend or as a text snippet. +You have now read the complete list of requirements for developing and releasing apps based on our app system in the Shopware Community Store. -### Register a cookie to the Cookie Consent Manager +If your app is a software app/interface with downstream costs, transaction fees, or service fees for the customer, we need to complete a technology partner agreement in order to activate your app. -We expect that every cookie set from the store URL is [registered in our Cookie Consent Manager](/docs/guides/plugins/plugins/storefront/add-cookie-to-manager). -We differentiate between "Technically required", "Comfort functions" and "Statistics and Tracking". -All cookies have to appear in the cookie configuration box in the frontend. +If you have any questions regarding the technology partner agreement, please contact our sales team by writing an email to [alliances@shopware.com](mailto:alliances@shopware.com) or calling **+44 (0) 203 095 2445 (UK) / 00 800 746 7626 0 (worldwide) / +49 (0) 25 55 / 928 85-0 (Germany)**. -### Shopping worlds/shopping experiences +## Storefront Guidelines -[Shopping worlds elements](#shopping-worldsstorytelling-elements) must include an element icon. -If the app is deleted, *Shopping Worlds* should continue to work flawlessly in the frontend. +### Testing the storefront -### Payment apps +Test the frontend and the checkout for new errors throughout the entire Storefront using the Browser Debug Console and also pay attention to JavaScript errors. -We check if the "pluginlogger" service is used for the debug/error.log and that logs are written in the directory /var/log/. -Log files must use this folder in every circumstance. -Another solution is to store them in the database. +### Links must include a title tag -### Every app accessing external API services +Links in the storefront and administration must include a meaningful "title tag". -A test button for optional API access data must be available. -If the API data is incorrect, an entry must appear in the event log file in the Shopware folder `/var/log/` respectively in the database. +### Images must include the alt-tag + +Links in the storefront and administration must include a meaningful "alt tag" or the original alt tag from the media manager. + +### Do not use `<hX>`-Tags + +The utilization of `<hX>`-tags in the storefront templates, which are set to `<meta name="robots" content="index,follow">`, is not permissible, as these tags are reserved exclusively for content purposes. +However, you may employ `<span class="h2">`, for instance. + +### Do not use inline-css in the storefront templates + +Use your own classes and let your CSS be compiled by the theme. + +### New controller URLs / XHR requests + +We check for new XHR/Document requests in the storefront as they must be accompanied by an `X-Robots-Tag` in the header request with the directive "noindex, nofollow.". +For further details, please refer to the [robots meta tag](https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag?hl=de#xrobotstag) article. + +If the app creates its own controller URLs set to "index, follow" and the URLs are accessible via the frontend, then these "app URLs" must also appear in the `sitemap.xml`. +In addition, these pages must include a valid canonical tag, their own meta description, and a title tag, which can be entered individually via the administration or as a text snippet. + +### Lighthouse A/B-Testing: + +Could you do an A/B test with *Lighthouse Audit* to check the performance and quality of your frontend app? +There should not be any drastic change in performance, accessibility values, or any new errors when activating the app. + +* **Testing tool** for A/B-Testing: + * [Google Lighthouse](https://developers.google.com/web/tools/lighthouse) + +### schema.org/Rich Snippets A/B-Testing: + +Do an A/B-Test with *Scheme.org's Structured Data Testing Tool* and *Google Rich Result Tester* to check the homepage, categories, and various product detail pages (incl. available products, unavailable products, products with no review, single review, many reviews with various ratings, out-of-stock products, products to be released in the future or any other kind of product configuration and products including ean, mpn, width, length, height, weight). +Also, could you check for duplicate entries as well as any new bugs? + +* **Testing tool** for A/B-Testing: + * [Schema Markup Validator of schema.org](https://validator.schema.org/) + * [Google Rich Result Tester](https://search.google.com/test/rich-results) + +### Usage of fonts from external sources + +If you are using external fonts (e.g., Google fonts, Fontawesome) or external services, the app store description must contain this information. + +Please be aware that you might have to edit your *data protection information*. +This info could be placed as a tooltip near the font settings of the app configuration. + +### Register your cookie to the Cookie Consent Manager + +We expect every cookie set from the store URL to be optional and not technically required for running shopware. +Therefore, the cookies had to be [registered in our Cookie Consent Manager](/docs/guides/plugins/plugins/storefront/add-cookie-to-manager). + +We differentiate between "Technically required", "Marketing" and "Comfort features". +All cookies must appear (unchecked) in the cookie configuration box in the frontend. + +## Administration guidelines + +### Menu entries in the main menu are not allowed + +Menu entries in the main menu of the administration are not allowed because of the look and feel. + +### Own media folder + +Customers must create their own media folders with the right thumbnail settings or use existing ones to upload images. + +If you use your own media folder, keep in mind that the folder and the included data had to be removed if selected during the uninstallation. + +### API test button + +* If your API corresponds via API credentials to external services, we expect an API test button. Apart from that, you can validate the required credentials while saving them in the app settings. -In this case, a status message must be displayed in the backend and in the Shopware log. +In this case, a status message must be displayed in the administration and Shopware log. +If the API data is incorrect, an entry must appear in the event log file in the Shopware folder `/var/log/` respectively in the database. -[Example for implementing an API Test Button into the System Config form](https://github.com/shyim/ShyimApiTest) +* **Example for implementing an API Test Button into the System Config form: + * [Github](https://github.com/shyim/ShyimApiTest) + +### Shopping experiences + +[Shopping worlds elements](https://developer.shopware.com/docs/concepts/commerce/content/shopping-experiences-cms.html#elements) must include an element icon. +If the app is deleted, *Shopping Worlds* should work flawlessly in the frontend. + +### Themes + +[Themes](https://developer.shopware.com/docs/guides/plugins/themes/) must include its own preview image. ### External technology/ Shopware Technology Partner (STP) apps @@ -375,13 +392,9 @@ Below is an example of implementing the tracking logic in their extensions: } ``` -### Menu entries in the main menu not allowed - -Menu entries in the main menu of the Administration are not allowed because of the look and feel. - ### Automatic code reviews with PhpStan and SonarQube -Our most current code review configurations that we use when uploading apps via the Shopware Account can be found on GitHub. +Our most current code review configurations when uploading apps via the Shopware Account can be found on GitHub. * [Code reviews for Shopware 6 on GitHub](https://github.com/shopwareLabs/store-plugin-codereview) @@ -390,7 +403,7 @@ Our most current code review configurations that we use when uploading apps via The following statements will be blocked as of 1st Oct. 2022: -die; exit; var_dump -[Refer to the list of the already existing blockers](https://s3.eu-central-1.amazonaws.com/wiki-assets.shopware.com/1657519735/blocker.txt). +* [Refer to the list of the already existing blockers](https://s3.eu-central-1.amazonaws.com/wiki-assets.shopware.com/1657519735/blocker.txt). ### Automated code tests with Cypress @@ -401,14 +414,9 @@ The project is driven by the *Friends of Shopware* group. You can contribute at * [Cypress Tests for Shopware 6](https://github.com/shopware/shopware/tree/trunk/src/Administration/Resources) ### Helpful tools for app developers - * [FroshPluginUploader](https://github.com/FriendsOfShopware/FroshPluginUploader): Tool for validating and uploading new SW6 app releases to the Community Store (GitHub Project from "Friends of Shopware")] * [Shopware CLI tools](https://github.com/shopwareLabs/sw-cli-tools): When you think about performance, these are various useful console helpers for generating data. -### Descriptions in your Shopware account - -[App descriptions in your Shopware account](#app-descriptions-in-your-shopware-account) must follow the checklist criterion. - ## Automatic code review - Errors ### The required composer.json file was not found @@ -416,12 +424,11 @@ The project is driven by the *Friends of Shopware* group. You can contribute at **Cause:** Error in composer.json One possible cause is that the technical app name from the Community Store or Account does not match the technical name entered in composer.json, or the app is incorrectly zipped. -The technical app name has to be stored in the last part of the composer.json located at composer.json > extra > shopware-plugin-class. -So take a look at the bootstrap class. Most of the errors is caused by the wrong technical name. +The technical app name must be stored in the composer.json, located at `composer.json` > extra > `shopware-plugin-class`. +Could you take a look at the bootstrap class? Most of the errors are caused by the wrong technical name. For example, "Swag\\MyPlugin\\SwagMyPluginSW6" instead of "Swag\\MyPlugin\\SwagMyPlugin". -[Here is an example](https://github.com/FriendsOfShopware/FroshPlatformPerformance/blob/master/composer.json#L20) of a valid composer.json. -See "[Plugin-Base Class](https://developers.shopware.com/designers-guide/javascript-statemanager-and-pluginbase/#plugin-base-class)" for more information. +[Example of a valid composer.json](https://github.com/FriendsOfShopware/FroshPlatformPerformance/blob/master/composer.json#L20). ### Ensure cross-domain messages are sent to the intended domain @@ -430,7 +437,7 @@ See ["Cross-document messaging domains should be carefully restricted"](https:// ### No bootstrapping file found. Expecting bootstrapping in The bootstrap cannot be found. -The reasons could be that the folder structure in the ZIP file is incorrect, there could be a typo, or a case-sensitive error in the app source (e.g., in the technical name). +The reasons could be that the folder structure in the ZIP file needs to be corrected, a typo, or a case-sensitive error in the app source (e.g., in the technical name). ### Class Shopware\Storefront\* not found @@ -446,15 +453,15 @@ Remember to register your cookie to the *Cookie Consent Manager*. Shopware always uses json_Encode exclusively - there is no other fallback. -### The lock file is not up-to-date with the latest changes in composer.json. You may be getting outdated dependencies. Run an update to update them +### The lock file is not up to date with the latest changes in composer.json. +You may need to get updated dependencies. Run an update to update them. The `composer.lock` in the app archive has to be deleted. ### Class Shopware\Core\System\Snippet\Files\SnippetFileInterface not found and could not be autoloaded In the Shopware 6 Early Access (EA) version, the mentioned class did not exist. -Therefore, the code review failed. -The reason for the problem is the following specification in the composer.json: +Therefore, the code review failed. The reason for the problem is the following specification in the composer.json: ```xml @@ -468,15 +475,15 @@ The reason for the problem is the following specification in the composer.json: ``` The Composer resolves this to "Whatever is the latest from these repositories" and then installs the Early Access version instead of the current Release Candidate. -This happens because an EA is not known by the Composer as a stability level (like stable or RC) and is, therefore, ultimately considered "stable". +This happens because the Composer does not know an EA as a stability level (like stable or RC) and is, therefore, ultimately considered "stable". The solution is to amend the requirement as follows: ```xml <pre>"require": { - "shopware/core": "^6.1", + "shopware/core": "~6.1.0", - "shopware/storefront": "^6.1" + "shopware/storefront": "~6.1.0" }, @@ -486,23 +493,32 @@ The solution is to amend the requirement as follows: This ensures that at least version Shopware 6.1 is installed, even if it is a Release Candidate. It will be preferred as soon as the final 6.1 is released. -### Unauthorized file formats or folders detected in the app. Please remove the following files/folders - -Not allowed folders and files: - - * .gitignore - * .DS_Store - * Thumbs.db - * .git, __MACOSX - * .zip - * .tar - * .tar.gz - * .phar - -## Note on Shopware technology partner contract for interfaces - -You have now read the complete list of requirements for developing and releasing apps based on our app system in the Shopware Community Store. - -If your app is a software app/interface with downstream costs, transaction fees, or service fees for the customer, we need to complete a technology partner agreement in order to activate your apps. - -If you have any questions regarding the technology partner agreement, please contact our sales team by writing an email to [alliances@shopware.com](mailto:alliances@shopware.com) or calling **+44 (0) 203 095 2445 (UK) / 00 800 746 7626 0 (worldwide) / +49 (0) 25 55 / 928 85-0 (Germany)**. +### Remove out-commented code from your source-code + +### Unauthorized file formats or folders detected in the app. + +Remove out-commented code, unused files and folders, and all dev-files from your binary. + +Here are some examples of not allowed folders and files: +* /__MACOSX +* /tests +* .gitignore +* .gitkeep +* .gitlab-ci.yml +* .DS_Store +* .editorconfig +* .git +* .gitignore +* .phar +* .prettierrc +* .shopware-extension.yml +* .tar +* .tar.gz +* .zip +* composer.lock +* package.json +* package-lock.json +* phpunitx.xml +* shell.nix +* Thumbs.db +* webpack.config.js diff --git a/resources/references/config-reference/server/caddy.md b/resources/references/config-reference/server/caddy.md new file mode 100644 index 000000000..6acbe551a --- /dev/null +++ b/resources/references/config-reference/server/caddy.md @@ -0,0 +1,26 @@ +# Caddy + +``` +mydomain.com { + header { + X-Frame-Options DENY + Referrer-Policy no-referrer-when-downgrade + } + + @svg { + file + path *.svg + } + + header @svg Content-Security-Policy "script-src 'none'" + + @default { + not path /theme/* /media/* /thumbnail/* /bundles/* /css/* /fonts/* /js/* /recovery/* /sitemap/* + } + + root * public + php_fastcgi 127.0.0.1:9000 + encode zstd gzip + file_server +} +``` \ No newline at end of file