diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..60011af3d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +# Shopware platform editor configuration normalization +# http://editorconfig.org/ + +# This is the top-most .editorconfig file; do not search in parent directories. +root = true + +# All files. +[*] +end_of_line = lf +indent_style = space +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore index daca60d87..da4affb20 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ .idea +/dictionary.dic +.DS_Store + +# VSCode-Project +/.vscode/ +!/.vscode/settings.json .vscode -/dictionary.dic \ No newline at end of file diff --git a/.lycheeignore b/.lycheeignore index 4b91669d0..8a0f3c7dd 100644 --- a/.lycheeignore +++ b/.lycheeignore @@ -4,4 +4,5 @@ https://nuxt.com/docs/guide/directory-structure/pages https://github.com/shopware/shopware/blob/trunk/src/Core/Content/Test/Product/SalesChannel/Listing/CachedProductListingRouteTest.php https://github.com/shopware/shopware/blob/trunk/src/Core/Content/Test/Product/Cart/ProductCartTest.php https://github.com/shopware/shopware/blob/6.4.17.0/src/Core/Framework/Update/Services/UpdateHtaccess.php -https://github.com/shopware/shopware/blob/trunk/src/Core/Checkout/Customer/Rule/IsNewCustomerRule.php \ No newline at end of file +https://github.com/shopware/shopware/blob/trunk/src/Core/Checkout/Customer/Rule/IsNewCustomerRule.php +https://www.tim-wellhausen.de/papers/ExpandAndContract/ExpandAndContract.html \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..9a1056a11 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "editor.tabSize": 2, + "editor.insertSpaces": true, + "editor.detectIndentation": false +} diff --git a/.wordlist.txt b/.wordlist.txt index f2ad70a40..417ba51d5 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -1,13 +1,6 @@ -ACL -ACLs -ADDR -ADR -ADRs -AOF -API's -APIs AbstractCaptcha AbstractStockUpdateFilter +accel AccountEditOrderPage AccountGuestLoginPage AccountLoginPage @@ -17,60 +10,108 @@ 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 -AsyncPaymentTransactionStruct +async AsynchronousPaymentHandlerInterface +AsyncPaymentTransactionStruct +atomicity AuditLogValueEntity +auth AuthenticationIdentityLoader +autocompletion +autogenerate +autogenerated +autoload +autoloaded +autoloader +autoloading +autom +autoprefixer +autowire +autowiring AvailableCombinationLoader AvgResult +awaitAndCheckNotification +axios B2B Component B2B Components B2B Suite -BBundle -BDD -BITV +backend Backend +backends +backface +backoff +backported +bAcl +bAjaxPanel BaseContext BasicExample +bAuditLog +bAuth +BBundle +BDD BeforeCartMergeEvent BeforeLineItemAddedEvent BeforeLineItemQuantityChangedEvent @@ -82,46 +123,76 @@ 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 -CDN -CDNs -CHANGELOG -CKEditor -CLI -CMS -CORS -CPUs -CSP -CSPs -CSRF -CSV +buyable +cacheable 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 @@ -130,15 +201,27 @@ 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 @@ -154,1046 +237,393 @@ ChildCount ChildCountField ChildrenAssociation ChildrenAssociationField +ci +CKEditor +classmap +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 -ConfigValidator +configs +configurator Configurator +ConfigValidator +confirmUrl 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 -CreateFromTrait -CreateTagAction +CPUs +createActionResponse +createCategoryFixture +createCmsFixture +createCustomerFixture 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 -CustomField +customerAware CustomerAware CustomerBeforeLoginEvent +customerGroup +customerGroupAware CustomerGroupAware CustomerGroupRegistrationPage CustomerGroupRule CustomerGroupStorer +customerHasFeature CustomerLoginEvent CustomerNumberRule +customerRecovery CustomerRecoveryAware CustomerRecoveryStorer CustomerStorer CustomerTagRule -DAL -DBAL -DDL -DESC -DIC -DIC EntityRepository -DOM -DOMPurify -DS -DSGVO -DSN -DSR -DTO -DTOs -DX +CustomField +customFields +customizability +customizable +customizations +customizer +cyclus 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 -Deleter -Deno -Denormalization -Denylist -Dependabot -DependencyInjection -Deployer -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 +Deleter demodemo demoshop deno +Deno +Denormalization denylist +Denylist +Dependabot dependencyInjection +DependencyInjection +deployer +Deployer deprecations +Deprecations dereference dereferenced +DESC describeFeatures destructuring +destructure +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 +Dockerfile dockware +Dockware dom -don'ts +DOM +DomainException +DomainExceptions +DOMPurify dont +don'ts dont's dr dragTo dropdown +DS +DSGVO +DSN dsr +DSR +dTH +DTO +DTOs dunglas duplications +DX +DynamoDB ean +EcmaScript 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 -fileSize fileinfo +FileLocator +FileReader +fileSize filesystem +Filesystem filesystems firstname +Fk +FkField flattenDeep +FloatField +FlowAction +FlowBuilder +FlowBuilderActionApp +FlowBuilderTriggerApp +FlowDispatcher +FlowEventAware +FlowExecutor +FlowStore +FlowStorer flyout +Flysystem focussed focussing +Fontawesome 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 @@ -1219,27 +649,40 @@ 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 @@ -1251,47 +694,72 @@ helpText herokuapp hideCookieBar hmac +HMAC +HMR +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 @@ -1301,49 +769,130 @@ 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 -localVue +ListField +ListingPrice +ListingPriceField +LoaderResolver 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 +MACOSX mailAware +MailAware +Mailcatcher +Mailhog +MailHog +MailService +MailStorer mailTemplates +MaintenancePage makefile mandatorily +ManufacturerAttributeDataSet manufacturerId +ManyToMany +ManyToManyAssociation +ManyToManyAssociationField +ManyToManyId +ManyToManyIdField +ManyToOne +ManyToOneAssociation +ManyToOneAssociationField mapErrors martinfowler masternode @@ -1352,91 +901,218 @@ matthiasnoback maxPurchase mbstring md +MediaDataSelection +MediaDataSet +MediaFolderDataSet mediaId mediaService +MemcachedSessionHandler memoization memoized +MenuOffcanvasPagelet mercure +Mercure mergeWith +MessageAware +MessageQueue +MessageStorer +MeteorAdminSDK +Methodize middleware +Middleware middlewares -minPurchase +MigrationCollection 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 +MyExtension 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 -offCanvasCart offcanvas +OffCanvas +offCanvasCart +OffcanvasCartPageLoadedEvent 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 +overrideComponentSetup paas +Paas +PaaS packagist -pageLoaders +Packagist +PageEvent 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 @@ -1444,49 +1120,121 @@ php phpdoc phpdocs phpinfo +PhpRedis phpstan +PhpStan +PHPStan +PHPStorm phpunit +PhpUnit +PHPunit +PHPUnit phpunit's phpunitx +PII +Pinia 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 +prepend preprocessor preprocessors preselect +Preselect preselection prettierrc previewable -previewComponent previewable +previewComponent +PreWriteValidationEvent 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 @@ -1494,125 +1242,248 @@ qa@shopware.com qty's quantityBefore quantityDelta +Quickstart +QuillJS +RabbitMq +RabbitMQ randomHex -reCAPTCHA +RDB readAsArrayBuffer readAsDataURL readAsText +README +Readonly realtime +rebasing 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 -repositoryFactory repositoryfacade +repositoryFactory +RepositoryIterator 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 -saleschannel +SalesChannelProductEntity 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 -setToInitialState settingsItem +setToInitialState +SFC +SFTP sha +SHA shakable shallowMount shippable +ShippingCountryRule +ShippingMethodPriceCollector +ShippingMethodRoute +ShippingMethodRule +ShippingStreetRule +ShippingZipCodeRule sho +ShopActivatedEvent +ShopDeactivatedEvent +ShopDeletedEvent shopId shopName +ShopNameAware +ShopNameStorer shopUrl shopware -shopware's +Shopware 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 @@ -1623,26 +1494,54 @@ subcontent subdirectories subdirectory subfolder +SubjectAware +SubjectStorer suboptimal subprocessor +Subprocessor subprocessors +SuggestPage supervisord svg +SVG +SVGs sw -swSelect +SwagAdvDevBundle +SwagB +SwagBasicExample +SwagBasicExampleTheme +SwagDigitalSalesRooms +SwagMigrationBundleExample +SwagMyPlugin +SwagMyPluginSW swoole +swSelect 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 @@ -1650,98 +1549,209 @@ th theming themself timeframe +TimeRangeRule tinyint +TinyMCE tipps +TipTap +TipTap's tl -to's +TLS todo tokenized +ToMany tooltip tooltips +Tooltips +ToOne +to's totalAmount tradeoff +transactional +TransactionalAction transactionCapture transactionId -transactional +TranslatedField +TranslationDataSet +TranslationsAssociation +TranslationsAssociationField transpiling +TreeBreadcrumb +TreeBreadcrumbField +TreeLevel +TreeLevelField +TreePath +TreePathField +TreeSelect triggerDeprecated +TriggerReload truthy tsx +TTL +TwigJS +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 -userRecovery +UserAware userland +userRecovery +UserStorer +Util utils +Utils uuid +Uuid +UUID +UUIDs +UUIDv +UX validator +Validator validators +Valkey varchar +VARCHAR +VCL +VCS ve +Vercel verifier -versionId versionable +VersionDataPayload +VersionDataPayloadField +VersionField +versionId viewport viewportHeight viewports vimeo +VirtualHosts +Vite +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 +XMLHttpRequest +XmlUtils +XorRule xpath +XPath +XQuartz xs xsd +XSS +XVFB yaml +YamlFileLoader yml youtube +YYYY +zipignore zlib zsh +ZSH zstd -zipignore -XMLHttpRequest diff --git a/guides/hosting/configurations/framework/routes.md b/guides/hosting/configurations/framework/routes.md new file mode 100644 index 000000000..1a80c4db7 --- /dev/null +++ b/guides/hosting/configurations/framework/routes.md @@ -0,0 +1,58 @@ +--- +nav: + title: Custom routes + position: 10 + +--- + +# Custom routes + +## Overview + +Your default routes in Shopware 6 are defined in the controllers of the core or your plugins. An example could be the wishlist route: + +```php + false], defaults: ['_noStore' => true], methods: ['GET'])] +public function index(Request $request, SalesChannelContext $context): Response +{ + $customer = $context->getCustomer(); + + if ($customer !== null && $customer->getGuest() === false) { + $page = $this->wishlistPageLoader->load($request, $context, $customer); + $this->hook(new WishlistPageLoadedHook($page, $context)); + } else { + $page = $this->guestPageLoader->load($request, $context); + $this->hook(new GuestWishlistPageLoadedHook($page, $context)); + } + + return $this->renderStorefront('@Storefront/storefront/page/wishlist/index.html.twig', ['page' => $page]); +} +``` + +It defines that your wishlist page is available at `/wishlist`. This is fine for an English-only shop, but for a multilingual shop, you might want to have a different route for each language. + +For example, you could have `/wishlist` for English and `/merkliste` for German. + +## Configuration + +To easily configure those routes, you can use the `routes.yaml` file in ROOT/config/routes/routes.yaml. Symfony loads this file, which allows you to define your custom `paths`, in our case, for the wishlist index page. + +```yaml +frontend.wishlist.page: + path: + en-GB: '/wishlist' + de-DE: '/merkliste' + controller: 'Shopware\Storefront\Controller\WishlistController::index' + methods: ['GET'] + defaults: + _noStore: true + _routeScope: ['storefront'] + options: + seo: false +``` + +You can configure the `path` with the **locales** (for example, `de-DE`) your shop uses. + +If you want to learn more about routes in Symfony, check out the [Symfony documentation](https://symfony.com/doc/current/routing.html#creating-routes-as-attributes). diff --git a/guides/hosting/configurations/observability/profiling.md b/guides/hosting/configurations/observability/profiling.md index 2a99e0f27..d5ce6761a 100644 --- a/guides/hosting/configurations/observability/profiling.md +++ b/guides/hosting/configurations/observability/profiling.md @@ -34,7 +34,7 @@ The OpenTelemetry profiler is not installed by default. Checkout the [OpenTeleme To add custom spans to the profiler, you can use the `Shopware\Core\Profiling\Profiler::trace` method: -```PHP +```php use Shopware\Core\Profiling\Profiler; $value = Profiler::trace('my-example-trace', function () { @@ -50,7 +50,7 @@ To add a custom profiler backend, you need to implement the `Shopware\Core\Profi The following example shows a custom profiler backend that logs the traces to the console: -```PHP +```php namespace App\Profiler; diff --git a/guides/hosting/configurations/shopware/environment-variables.md b/guides/hosting/configurations/shopware/environment-variables.md index 04003e2ae..b9698c331 100644 --- a/guides/hosting/configurations/shopware/environment-variables.md +++ b/guides/hosting/configurations/shopware/environment-variables.md @@ -9,32 +9,33 @@ nav: 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`) | +| 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) | +| `ENABLE_SERVICES` | `auto` | Determines if services are enabled, auto detects that based on `APP_ENV`, other possible values are `true` & `false` | +| `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/scheduled-task.md b/guides/hosting/infrastructure/scheduled-task.md index 0f11460e9..a9236e517 100644 --- a/guides/hosting/infrastructure/scheduled-task.md +++ b/guides/hosting/infrastructure/scheduled-task.md @@ -80,10 +80,4 @@ bin/console messenger:consume scheduler_shopware On startup of this command reads the `scheduled_task` database table and applies the stored intervals, an entry in this table is optional. In the event that these intervals are modified in the database, it is necessary to restart the command for the updated intervals to take effect. To deactivate tasks, set status to `Shopware\Core\Framework\MessageQueue\ScheduledTask\ScheduledTaskDefinition::STATUS_INACTIVE` in this table, and restart the `consume` command. -## Debugging scheduled tasks - -You can directly run a single scheduled task without the queue. This is useful for debugging purposes or to have better control of when and which tasks are executed. You can use `bin/console scheduled-task:run-single ` to run a single task. Example: - -```shell -bin/console scheduled-task:run-single log_entry.cleanup -``` + diff --git a/guides/hosting/installation-updates/deployments/deployment-helper.md b/guides/hosting/installation-updates/deployments/deployment-helper.md index 1f1639b45..15e74c679 100644 --- a/guides/hosting/installation-updates/deployments/deployment-helper.md +++ b/guides/hosting/installation-updates/deployments/deployment-helper.md @@ -70,7 +70,7 @@ deployment: # the key is the extension name (app or plugin) MyPlugin: # Same as exclude - state: ignored + state: ignore AnotherPlugin: # This plugin can be installed, but should be inactive diff --git a/guides/hosting/installation-updates/deployments/deployment-with-deployer.md b/guides/hosting/installation-updates/deployments/deployment-with-deployer.md index ffe7f72e1..28d0b373e 100644 --- a/guides/hosting/installation-updates/deployments/deployment-with-deployer.md +++ b/guides/hosting/installation-updates/deployments/deployment-with-deployer.md @@ -238,7 +238,9 @@ variables: Deploy: stage: deploy # Tags are useful to only use runners that are safe or meet specific requirements - image: shopware/shopware-cli:latest-php-8.3 + image: + name: shopware/shopware-cli:latest + entrypoint: [ "/bin/sh", "-c" ] before_script: # First, we need to execute all commands that are defined in the `configureSSHAgent` variable. - *configureSSHAgent diff --git a/guides/hosting/performance/k6.md b/guides/hosting/performance/k6.md index e045525fe..085ca4cac 100644 --- a/guides/hosting/performance/k6.md +++ b/guides/hosting/performance/k6.md @@ -68,7 +68,7 @@ The command `framework:demodata` can also execute multiple times in parallel, so 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 +```javascript // example.js import { accountRegister, @@ -127,7 +127,7 @@ so now the test will run with 10 virtual users and 100 iterations. You can also run multiple scenarios in the same file. To do this, you can define them in the options like so: -```js +```javascript // example.js import { productChangePrice, productChangeStocks, fetchBearerToken, useCredentials, productImport } from "./helpers/api.js"; import { diff --git a/guides/hosting/performance/performance-tweaks.md b/guides/hosting/performance/performance-tweaks.md index 3b3224f0a..670111fa4 100644 --- a/guides/hosting/performance/performance-tweaks.md +++ b/guides/hosting/performance/performance-tweaks.md @@ -35,26 +35,47 @@ shopware: ### Delayed invalidation -A delay for cache invalidation can be activated for systems with a high update frequency for the inventory (products, categories). Once the instruction to delete the cache entries for a specific product or category occurs, they are not deleted instantly but processed by a background task later. Thus, if two processes invalidate the cache in quick succession, the timer for the invalidation of this cache entry will only reset. +A delay for cache invalidation can be activated for systems with a high update frequency for the inventory (products, categories). Once the instruction to delete the cache entries for a specific product or category occurs, they are not deleted instantly but processed later by a background task. Thus, if two processes invalidate the cache in quick succession, the timer for the invalidation of this cache entry will only reset. By default, the scheduled task will run every 20 seconds, but the interval can be adjusted over the `scheduled_taks` DB table, by setting the `run_interval` to the desired value (it is configured in seconds) for the entry with the name `shopware.invalidate_cache`. +::: warning +If you enable delayed cache invalidation, you must set up a worker to run [Scheduled Tasks](../infrastructure/scheduled-task), e.g., using the [Message Queue](../infrastructure/message-queue). +::: + +There are two possible storages/adapters for delayed cache invalidation: Redis and MySQL. Redis is preferred since it handles retrieving and deleting keys in an atomic manner. MySQL also supports it, but it's more complicated, and at a certain load, deadlocks are inevitable. If you already use Redis, use it also for the delayed cached. The MySQL adapter should only be used when you cannot use Redis. + +Redis: + ```yaml # config/packages/prod/shopware.yaml shopware: cache: invalidation: - delay: 1 + delay: 1 # 0 = disabled, 1 = enabled delay_options: storage: redis connection: 'ephemeral' # connection name from redis configuration ``` +MySQL: + +```yaml +# config/packages/prod/shopware.yaml +shopware: + cache: + invalidation: + delay: 1 # 0 = disabled, 1 = enabled + delay_options: + storage: mysql +``` + ## MySQL configuration Shopware sets some MySQL configuration variables on each request to ensure it works in any environment. You can disable this behavior if you have correctly configured your MySQL server. - Make sure that `group_concat_max_len` is by default higher or equal to `320000` - Make sure that `sql_mode` doesn't contain `ONLY_FULL_GROUP_BY` +- Make sure that `time_zone` is set to UTC (`default-time-zone='+00:00'` in `my.cnf`) and then you can set `SQL_SET_DEFAULT_SESSION_VARIABLES=0` to your `.env` file ## SQL is faster than DAL @@ -273,7 +294,11 @@ This is available starting with Shopware 6.6.10.0 The **Product Stream Indexer** is a background process that creates a mapping table of products to their streams. It is used to find which category pages are affected by product changes. On a larger inventory set or a high update frequency, the **Product Stream Indexer** can be a performance bottleneck. -Disadvantages are: +To disable the Product Stream Indexer, you can set the following configuration: + +<<< @/docs/snippets/config/product_stream.yaml + +Disabling the Product Stream Indexer has the following disadvantages: - When you change a product in a stream, the category page is not updated until the HTTP cache expires - You could also explicitly update the category page containing the stream to workaround if that is a problem @@ -282,3 +307,55 @@ Disadvantages are: To disable the Product Stream Indexer, you can set the following configuration: <<< @/docs/snippets/config/product_stream.yaml + +## Enable the Speculation Rules API + +::: info +This feature is available starting with Shopware 6.6.10.0 +::: + +The Speculation Rules API allows browsers to pre-render pages based on user interactions or immediately, depending on the eagerness setting. +This can improve the perceived performance of a website by loading pages in the background before the user navigates to them. + +You can enable that **experimental feature** via `Admin > Settings > System > Storefront`. The JavaScript Plugin will then +check if the [Browser supports the Speculation Rules API](https://caniuse.com/mdn-http_headers_speculation-rules) and if so, +it will add a script tag to the head of the document. For the [eagerness setting](https://developer.chrome.com/docs/web-platform/prerender-pages#eagerness) +we are using `moderate` everywhere. That means **a user must interact** with a link to execute the pre-rendering. + +::: info +Keep in mind that pre-rendering puts extra load on your server and also can affect your [Analytics](https://developer.chrome.com/docs/web-platform/prerender-pages#impact-on-analytics). +::: + +## Optimize class loading + +### opcache.max_accelerated_files + +PHP loads many classes on each request, which can be a performance bottleneck. To optimize this, make sure `opcache.max_accelerated_files` is set to `20000` or higher. + +### classmap-authoritative + +Additionally, when all plugins are installed directly through Composer and managed by Composer, you can generate a static autoloader which does no class mapping at runtime. + +To enable this, set the following configuration in your `composer.json`: + +```diff +"config": { + "allow-plugins": { + "symfony/flex": true, + "symfony/runtime": true + }, + "optimize-autoloader": true, ++ "classmap-authoritative": true, + "sort-packages": true +}, +``` + +For more information, check out the [Composer documentation](https://getcomposer.org/doc/articles/autoloader-optimization.md#optimization-level-2-a-authoritative-class-maps). + +### opcache.preload + +To completely reduce the class loading at runtime, you can enable `opcache.preload` by setting it to `/var/cache/opcache-preload.php` and `opcache.preload_user` to the user running the PHP process. This will preload all classes into the opcache on PHP-FPM startup and reduce the class loading at runtime. + +::: warning +When using `opcache.preload`, you need to **restart** the PHP-FPM after each modification to reload the preloaded classes. +::: diff --git a/guides/installation/requirements.md b/guides/installation/requirements.md index 0bef6bec8..0854e865a 100644 --- a/guides/installation/requirements.md +++ b/guides/installation/requirements.md @@ -31,18 +31,19 @@ You can use these commands to check your actual environment: * `memory_limit` : 512M minimum * `max_execution_time` : 30 seconds minimum * Extensions: + * `ext-amqp` (only required if you plan to use a message queue, which is the default on PaaS) * `ext-curl` * `ext-dom` * `ext-fileinfo` * `ext-gd` - * `ext-iconv` + * `ext-iconv` * `ext-intl` * `ext-json` * `ext-libxml` - * `ext-mbstring` + * `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-pcre` + * `ext-pdo` * `ext-pdo_mysql` * `ext-phar` * `ext-simplexml` diff --git a/guides/plugins/apps/administration/add-cms-element-via-admin-sdk.md b/guides/plugins/apps/administration/add-cms-element-via-admin-sdk.md index f4933d50f..e56b65e5b 100644 --- a/guides/plugins/apps/administration/add-cms-element-via-admin-sdk.md +++ b/guides/plugins/apps/administration/add-cms-element-via-admin-sdk.md @@ -51,7 +51,7 @@ When our extension is finished, you will get the following file structure: Everything starts in the `main.ts` file: -```js +```javascript import 'regenerator-runtime/runtime'; import { location } from '@shopware-ag/meteor-admin-sdk'; @@ -88,7 +88,7 @@ Observe that every file is named according to the component and prefixed with `s Let us see how the component loading via `viewRenderer.ts` looks like: -```js +```javascript import Vue from 'vue'; import { location } from '@shopware-ag/meteor-admin-sdk'; @@ -135,7 +135,7 @@ Those will be available after **registering the component**, which we will do in For this topic we head to `mainCommands.ts`, since the registration of CMS elements is something to be done in a global scope. -```js +```javascript import { cms } from '@shopware-ag/meteor-admin-sdk'; const CMS_ELEMENT_NAME = 'swag-dailymotion'; @@ -181,7 +181,7 @@ You can vary the structure of `swag-dailymotion`'s contents and create folders f Let's go through each of the files to talk about it's contents, starting with `swag-dailymotion-config.ts`: -```js +```javascript import Vue from 'vue' import { data } from "@shopware-ag/meteor-admin-sdk"; import CONSTANTS from "../../base/mainCommands"; @@ -247,7 +247,7 @@ With these small additions to typical CMS element behavior, you have already don Now let's have a look at the result of `swag-dailymotion-element.ts`: -```js +```javascript import Vue from 'vue' import { data } from "@shopware-ag/meteor-admin-sdk"; import CONSTANTS from "../../base/mainCommands"; @@ -311,7 +311,7 @@ It initially fetches the `element` data, as you've already seen it in the config Lastly, have a look at `swag-dailymotion-preview.ts`. In most cases, not much logic is to be found here, since this is the preview loaded when choosing a CMS element for your block. It makes sense to show an example preview, a miniature skeleton of the result, or just the Dailymotion logo. Therefore, the following code will suffice for your example extension: -```js +```javascript import Vue from 'vue' export default Vue.extend({ diff --git a/guides/plugins/apps/administration/add-custom-action-button.md b/guides/plugins/apps/administration/add-custom-action-button.md index dd334aa97..7e768751a 100644 --- a/guides/plugins/apps/administration/add-custom-action-button.md +++ b/guides/plugins/apps/administration/add-custom-action-button.md @@ -20,7 +20,7 @@ One extension possibility in the Administration is the ability to add custom act To get those buttons, you start in the `admin` section of your manifest file. There you can define `` elements in order to add your button, as seen as below: ```xml -// manifest.xml + @@ -297,7 +297,7 @@ This feature was added in Shopware 6.4.10.0, previous versions don't support rel To use custom endpoints as the target url for action buttons you can define the target url as a relative url in your apps manifest.xml: ```xml -// manifest.xml + diff --git a/guides/plugins/apps/administration/add-custom-modules.md b/guides/plugins/apps/administration/add-custom-modules.md index 4ddd1f2d9..7fdb4df60 100644 --- a/guides/plugins/apps/administration/add-custom-modules.md +++ b/guides/plugins/apps/administration/add-custom-modules.md @@ -36,7 +36,7 @@ To configure your module, you can set it up with with some additional attributes Additionally you can define `label` elements inside of your `module` element, to set up how your module will be displayed in the admin menu. ```xml -// manifest.xml + @@ -136,7 +136,7 @@ When you define a module, it gets automatically loaded by the Administration. Ad The navigation id of your modules always uses the pattern `app--`. So, within your manifest you can add a reference to modules that you just created: ```xml -// manifest.xml + @@ -176,7 +176,7 @@ Your main module can be defined by adding a `main-module` element within your `a To avoid mixing other modules with your main module, we decided to separate the main module from modules with navigation entries. You can still use the same URL on both, a module that is available through the menu and your main module. ```xml -// manifest.xml + diff --git a/guides/plugins/apps/app-base-guide.md b/guides/plugins/apps/app-base-guide.md index a5a12ad57..4e9bc58be 100644 --- a/guides/plugins/apps/app-base-guide.md +++ b/guides/plugins/apps/app-base-guide.md @@ -38,7 +38,7 @@ To get started with your app, create an `apps` folder inside the `custom` folder The manifest file is the central point of your app. It defines the interface between your app and the Shopware instance. It provides all the information concerning your app, as seen in the minimal version below: ```xml -// manifest.xml + @@ -299,7 +299,7 @@ Since version 6.4.12.0, your app can also request additional non-CRUD privileges Sample permissions to read, create and update products, delete orders, as well as reading the cache configuration look like this: ```xml -// manifest.xml + diff --git a/guides/plugins/apps/app-scripts/cart-manipulation.md b/guides/plugins/apps/app-scripts/cart-manipulation.md index 090e1708a..32db3176a 100644 --- a/guides/plugins/apps/app-scripts/cart-manipulation.md +++ b/guides/plugins/apps/app-scripts/cart-manipulation.md @@ -96,7 +96,7 @@ In general, Shopware prices consist of gross and net prices and are currency dep You can define price fields for [custom fields](../custom-data/custom-fields) ```xml -// manifest.xml + custom_field_test 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 6ca5306cd..2f771f798 100644 --- a/guides/plugins/apps/app-sdks/javascript/01-getting_started.md +++ b/guides/plugins/apps/app-sdks/javascript/01-getting_started.md @@ -21,7 +21,7 @@ After the installation, you can use the SDK in your project. Here is an example: ## Registration process -```js +```javascript import { AppServer, InMemoryShopRepository } from '@shopware-ag/app-server-sdk' const app = new AppServer({ diff --git a/guides/plugins/apps/app-sdks/javascript/02-lifecycle.md b/guides/plugins/apps/app-sdks/javascript/02-lifecycle.md index 91caa67ef..06b07c877 100644 --- a/guides/plugins/apps/app-sdks/javascript/02-lifecycle.md +++ b/guides/plugins/apps/app-sdks/javascript/02-lifecycle.md @@ -32,7 +32,7 @@ The lifecycle registration in the `manifest.xml` would look like this: The implementation is similar to [Registration](./01-getting_started), -```js +```javascript import { AppServer, InMemoryShopRepository } from '@shopware-ag/app-server-sdk' const app = new AppServer({ diff --git a/guides/plugins/apps/app-sdks/javascript/03-context.md b/guides/plugins/apps/app-sdks/javascript/03-context.md index f7d7fc1f3..ae53f8e08 100644 --- a/guides/plugins/apps/app-sdks/javascript/03-context.md +++ b/guides/plugins/apps/app-sdks/javascript/03-context.md @@ -11,7 +11,7 @@ The ContextResolver helps you to validate the Request, resolve the Shop and prov ## Usage -```js +```javascript import { AppServer } from '@shopware-ag/app-server-sdk' const app = new AppServer(/** ... */); diff --git a/guides/plugins/apps/custom-data/custom-entities.md b/guides/plugins/apps/custom-data/custom-entities.md index b6bd140a4..6926584e9 100644 --- a/guides/plugins/apps/custom-data/custom-entities.md +++ b/guides/plugins/apps/custom-data/custom-entities.md @@ -67,7 +67,7 @@ To enable the usage of custom fields, the `custom-fields-aware` setting should b Now you will find your entity in the "Entity Type" select when creating a custom field of type "Entity Select". Without a snippet label for the entity, it will display as `custom_entity_bundle.label`. You can create a snippet to add a label like so: -```js +```javascript // Resources/app/administration/snippet/en-GB.json { "custom_entity_bundle": { diff --git a/guides/plugins/apps/flow-builder/add-custom-flow-actions-from-app-system.md b/guides/plugins/apps/flow-builder/add-custom-flow-actions-from-app-system.md index 084fe0076..df5342110 100644 --- a/guides/plugins/apps/flow-builder/add-custom-flow-actions-from-app-system.md +++ b/guides/plugins/apps/flow-builder/add-custom-flow-actions-from-app-system.md @@ -60,7 +60,7 @@ From 6.5.2.0, you can define the flow action in `flow.xml`. The `flow-action.xml The manifest file is the central point of your app. It defines the interface between your app and the Shopware instance. It provides all the information concerning your app, as seen in the minimal version below: ```xml -// manifest.xml + diff --git a/guides/plugins/apps/flow-builder/add-custom-flow-triggers-from-app-system.md b/guides/plugins/apps/flow-builder/add-custom-flow-triggers-from-app-system.md index e161bc30b..48adbcfe3 100644 --- a/guides/plugins/apps/flow-builder/add-custom-flow-triggers-from-app-system.md +++ b/guides/plugins/apps/flow-builder/add-custom-flow-triggers-from-app-system.md @@ -59,7 +59,7 @@ To get started with your app, create an `apps` folder inside the `custom` folder The manifest file is the central point of your app. It defines the interface between your app and the Shopware instance. It provides all the information concerning your app, as seen in the minimal version below: ```xml -// manifest.xml + @@ -216,7 +216,7 @@ Snippet keys should be defined based on your trigger name defined at `` in ``` -```js +```javascript // custom/apps/FlowBuilderTriggerApp/Resources/app/administration/snippet/en-GB.json { "sw-flow-custom-event": { diff --git a/guides/plugins/apps/shipping-methods.md b/guides/plugins/apps/shipping-methods.md index ba68601d7..313e1bec7 100644 --- a/guides/plugins/apps/shipping-methods.md +++ b/guides/plugins/apps/shipping-methods.md @@ -28,7 +28,7 @@ The following example represents the most minimal configuration for a shipping m Ensure that the `` of your shipping method remains unchanged, as Shopware will deactivate or delete shipping methods that do no longer appear in the manifest during app updates. ```xml -// manifest.xml + diff --git a/guides/plugins/apps/starter/starter-admin-extension.md b/guides/plugins/apps/starter/starter-admin-extension.md index c3394aba8..260cc15c1 100644 --- a/guides/plugins/apps/starter/starter-admin-extension.md +++ b/guides/plugins/apps/starter/starter-admin-extension.md @@ -41,7 +41,7 @@ When you are using a self-hosted Shopware version, you can also create the proje Next, we will put our basic configuration into the file we just created. ```xml -// manifest.xml + @@ -113,7 +113,7 @@ The final step of the setup is to configure your app to use that file as an entr To do that, we have to add an `admin` section to our `manifest.xml` file and pass it into the `base-app-url` tag: ```xml -// manifest.xml + diff --git a/guides/plugins/apps/storefront/cookies-with-apps.md b/guides/plugins/apps/storefront/cookies-with-apps.md index ede118903..d2cffd465 100644 --- a/guides/plugins/apps/storefront/cookies-with-apps.md +++ b/guides/plugins/apps/storefront/cookies-with-apps.md @@ -18,7 +18,7 @@ You should be familiar with the concept of apps. To add new cookies to the cookie consent manager, you can add a `cookies` section to your `manifest.xml`. Inside this section, you can add new `cookie` elements, as shown in the following example. Note that you don't need a `setup` section in your `manifest.xml` since extending the Storefront doesn't need a registration nor an own server to run. ```xml -// manifest.xml + @@ -55,7 +55,7 @@ When adding multiple cookies through your app it may become handy to group them. To add a cookie group, you can add a `groups` section within your `cookies` section in your `manifest.xml`. In the following example, we use the cookie that we created in the previous section but display it in a cookie group: ```xml -// manifest.xml + diff --git a/guides/plugins/apps/storefront/index.md b/guides/plugins/apps/storefront/index.md index 6abeb3b6f..d7581efd9 100644 --- a/guides/plugins/apps/storefront/index.md +++ b/guides/plugins/apps/storefront/index.md @@ -46,7 +46,7 @@ Note that this feature was introduced in Shopware 6.4.12.0, and is not supported You may want your templates loaded before or after other extensions. To do so, you can define a `template-load-priority` inside your `manifest.xml`. The default value to this is 0, with positive numbers your template will be loaded earlier, and with negative numbers later. ```xml -// manifest.xml + diff --git a/guides/plugins/plugins/administration/add-rule-assignment-configuration.md b/guides/plugins/plugins/administration/advanced-configuration/add-rule-assignment-configuration.md similarity index 98% rename from guides/plugins/plugins/administration/add-rule-assignment-configuration.md rename to guides/plugins/plugins/administration/advanced-configuration/add-rule-assignment-configuration.md index 6f302884c..7eb52c277 100644 --- a/guides/plugins/plugins/administration/add-rule-assignment-configuration.md +++ b/guides/plugins/plugins/administration/advanced-configuration/add-rule-assignment-configuration.md @@ -15,7 +15,7 @@ The rule assignment configuration is available from Shopware Version 6.4.8.0 You want to create a custom card in the rule assignment, where you can add or delete assignments? This guide gets you covered on this topic. Based on an example of the configuration of the `Dynamic Access` plugin, you will see how to write your configuration. -![Rule config](../../../../assets/add-rule-assignment-configuration-0.png) +![Rule config](../../../../../assets/add-rule-assignment-configuration-0.png) ## Prerequisites @@ -162,7 +162,7 @@ Let's go through the most important entries, how to configure your rule assignme If you want to provide to delete an assignment, you have to define the `deleteContext`. There are two types of the `deleteContext`. The first one is the `one-to-many` type, which link to a column of the assignment entity like this: -```js +```javascript // Example of a one-to-many deleteContext deleteContext: { type: 'one-to-many', @@ -173,7 +173,7 @@ deleteContext: { The other type is `many-to-many`, which has to link to the `ManyToManyAssociationField` of the extension like this: -```js +```javascript // Example of a many-to-many deleteContext deleteContext: { type: 'many-to-many', @@ -187,7 +187,7 @@ deleteContext: { If you want to provide to add an assignment, you have to define the `addContext`. This context has the same two types as the `deleteContext` (see above), but the `addContext` has more options to fill out, because an add assignment modal has to be configured: -```js +```javascript // Example of a one-to-many addContext addContext: { type: 'one-to-many', @@ -241,7 +241,7 @@ Also, the context needs the `column` of the assignment and the `searchColumn` of A context of the `many-to-many` type would look like this: -```js +```javascript // Example of a many-to-many addContext addContext: { type: 'many-to-many', diff --git a/guides/plugins/plugins/administration/add-shortcuts.md b/guides/plugins/plugins/administration/advanced-configuration/add-shortcuts.md similarity index 100% rename from guides/plugins/plugins/administration/add-shortcuts.md rename to guides/plugins/plugins/administration/advanced-configuration/add-shortcuts.md diff --git a/guides/plugins/plugins/administration/extending-webpack.md b/guides/plugins/plugins/administration/advanced-configuration/extending-webpack.md similarity index 100% rename from guides/plugins/plugins/administration/extending-webpack.md rename to guides/plugins/plugins/administration/advanced-configuration/extending-webpack.md diff --git a/guides/plugins/plugins/administration/modify-blacklist-for-dynamic-product-groups.md b/guides/plugins/plugins/administration/advanced-configuration/modify-blacklist-for-dynamic-product-groups.md similarity index 100% rename from guides/plugins/plugins/administration/modify-blacklist-for-dynamic-product-groups.md rename to guides/plugins/plugins/administration/advanced-configuration/modify-blacklist-for-dynamic-product-groups.md diff --git a/guides/plugins/plugins/administration/customizing-components.md b/guides/plugins/plugins/administration/customizing-components.md deleted file mode 100644 index 514a0f309..000000000 --- a/guides/plugins/plugins/administration/customizing-components.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -nav: - title: Customizing components - position: 170 - ---- - -# Customizing components - -The Shopware 6 Administration allows you to override twig blocks to change its content. -This guide will teach you the basics of overriding parts of the Administration. - -## Prerequisites - -All you need for this guide is a running Shopware 6 instance, the files and preferably a registered module. -Of course, you'll have to understand JavaScript and have a basic familiarity with TwigJS, the templating engine, used in the Administration. -However, that's a prerequisite for Shopware as a whole and will not be taught as part of this documentation. - -## Finding the block to override - -In this guide we want to change the heading of the Shopware 6 dashboard to be `Welcome to a customized Administration` instead of `Welcome to Shopware 6`. -To do this we first need to find an appropriate twig block to override. -We don't want to replace too much but also to not override too little of the Administration. -In this case we only want to override the headline and not links or anything else on the page. -Looking at the twig markup for the dashboard [here](https://github.com/shopware/shopware/blob/trunk/src/Administration/Resources/app/administration/src/module/sw-dashboard/page/sw-dashboard-index/sw-dashboard-index.html.twig), -suggests that we only need to override the Twig block with the name `sw_dashboard_index_content_intro_content_headline` to achieve our goal. - -## Preparing the override - -Now that we know where to place our override, we need to decide what to override it with. -In this very simple example it suffices to create a twig file, declare a block with the name we previously found and to insert our new header into the block. - -```text - -{% block sw_dashboard_index_content_intro_content_headline %} -

- Welcome to a customized component -

-{% endblock %} -``` - -This overrides the entire Twig block with our new markup. -However, if we want to retain the original content of the Twig block and just add our markup to the existing one, we can do that by including a {% parent %} somewhere in the Twig block. -Learn more about the capabilities of twig.js [here](https://github.com/twigjs/twig.js/wiki). - -As you might have noticed the heading we just replaced had a `{ $tc() }` [string interpolation](https://vuejs.org/v2/guide/syntax.html#Text) which is used to make it multilingual. -Learn more about internationalization in the Shopware 6 Administration and about adding your own snippets to the Administration [here](adding-snippets). - -## Applying the override - -Registering the override of the Vue component is done by using the override method of our ComponentFactory. -This could be done in any `.js` file, which then has to be later imported, but we'll place it in `/src/Resources/app/administration/src/sw-dashboard-index-override/index.js`. - -```javascript -import template from './sw-dashboard-index.html.twig'; - -Shopware.Component.override('sw-dashboard-index', { - template -}); -``` - -The first parameter matches the component to override, the second parameter has to be an object containing the actually overridden properties , e.g. the new twig template extension for this component. - -## Loading the JavaScript File - -The main entry point to customize the Administration via a plugin is the `main.js` file. -It has to be placed into the `/src/Resources/app/administration/src` directory in order to be automatically found by Shopware 6. - -The only thing now left to just add an import for our of previously created `./sw-dashboard-index-override/index.js` in the `main.js`: - -```javascript -import './sw-dashboard-index-override/'; -``` - -## More interesting topics - -* [Customizing templates](writing-templates) -* [Customizing via custom styles](add-custom-styles) -* [Using base components](using-base-components) diff --git a/guides/plugins/plugins/administration/handling-media.md b/guides/plugins/plugins/administration/data-handling-processing/handling-media.md similarity index 100% rename from guides/plugins/plugins/administration/handling-media.md rename to guides/plugins/plugins/administration/data-handling-processing/handling-media.md diff --git a/guides/plugins/plugins/administration/search-custom-data.md b/guides/plugins/plugins/administration/data-handling-processing/search-custom-data.md similarity index 100% rename from guides/plugins/plugins/administration/search-custom-data.md rename to guides/plugins/plugins/administration/data-handling-processing/search-custom-data.md diff --git a/guides/plugins/plugins/administration/the-shopware-object.md b/guides/plugins/plugins/administration/data-handling-processing/the-shopware-object.md similarity index 97% rename from guides/plugins/plugins/administration/the-shopware-object.md rename to guides/plugins/plugins/administration/data-handling-processing/the-shopware-object.md index 8a95d5913..0d224f6d3 100644 --- a/guides/plugins/plugins/administration/the-shopware-object.md +++ b/guides/plugins/plugins/administration/data-handling-processing/the-shopware-object.md @@ -80,7 +80,7 @@ TypeScript declarations are available from Shopware Version 6.4.4.0 The Shopware Administration is written in pure JavaScript. To provide you with the benefits of TypeScript and the best possible developer experience while working in JavaScript files we're providing TypeScript declaration files within the Administration. These files are helping you to understand how the Shopware object works and what arguments you have to provide for example when you're creating a new module or registering a new component. -![TypeScript declarations example](../../../../assets/typescript-declaration-shopware-module.gif) +![TypeScript declarations example](../../../../../assets/typescript-declaration-shopware-module.gif) In the example above you can see how the TypeScript declarations are helping you to register a module. It automatically marks your code and points out what is missing. diff --git a/guides/plugins/plugins/administration/using-custom-fields.md b/guides/plugins/plugins/administration/data-handling-processing/using-custom-fields.md similarity index 100% rename from guides/plugins/plugins/administration/using-custom-fields.md rename to guides/plugins/plugins/administration/data-handling-processing/using-custom-fields.md diff --git a/guides/plugins/plugins/administration/using-data-handling.md b/guides/plugins/plugins/administration/data-handling-processing/using-data-handling.md similarity index 100% rename from guides/plugins/plugins/administration/using-data-handling.md rename to guides/plugins/plugins/administration/data-handling-processing/using-data-handling.md diff --git a/guides/plugins/plugins/administration/using-the-data-grid-component.md b/guides/plugins/plugins/administration/data-handling-processing/using-the-data-grid-component.md similarity index 100% rename from guides/plugins/plugins/administration/using-the-data-grid-component.md rename to guides/plugins/plugins/administration/data-handling-processing/using-the-data-grid-component.md diff --git a/guides/plugins/plugins/administration/using-vuex-state.md b/guides/plugins/plugins/administration/data-handling-processing/using-vuex-state.md similarity index 100% rename from guides/plugins/plugins/administration/using-vuex-state.md rename to guides/plugins/plugins/administration/data-handling-processing/using-vuex-state.md diff --git a/guides/plugins/plugins/administration/add-mixins.md b/guides/plugins/plugins/administration/mixins-directives/add-mixins.md similarity index 100% rename from guides/plugins/plugins/administration/add-mixins.md rename to guides/plugins/plugins/administration/mixins-directives/add-mixins.md diff --git a/guides/plugins/plugins/administration/adding-directives.md b/guides/plugins/plugins/administration/mixins-directives/adding-directives.md similarity index 100% rename from guides/plugins/plugins/administration/adding-directives.md rename to guides/plugins/plugins/administration/mixins-directives/adding-directives.md diff --git a/guides/plugins/plugins/administration/using-mixins.md b/guides/plugins/plugins/administration/mixins-directives/using-mixins.md similarity index 100% rename from guides/plugins/plugins/administration/using-mixins.md rename to guides/plugins/plugins/administration/mixins-directives/using-mixins.md diff --git a/guides/plugins/plugins/administration/add-custom-component.md b/guides/plugins/plugins/administration/module-component-management/add-custom-component.md similarity index 100% rename from guides/plugins/plugins/administration/add-custom-component.md rename to guides/plugins/plugins/administration/module-component-management/add-custom-component.md diff --git a/guides/plugins/plugins/administration/add-custom-field.md b/guides/plugins/plugins/administration/module-component-management/add-custom-field.md similarity index 100% rename from guides/plugins/plugins/administration/add-custom-field.md rename to guides/plugins/plugins/administration/module-component-management/add-custom-field.md diff --git a/guides/plugins/plugins/administration/add-custom-module.md b/guides/plugins/plugins/administration/module-component-management/add-custom-module.md similarity index 100% rename from guides/plugins/plugins/administration/add-custom-module.md rename to guides/plugins/plugins/administration/module-component-management/add-custom-module.md diff --git a/guides/plugins/plugins/administration/module-component-management/customizing-components.md b/guides/plugins/plugins/administration/module-component-management/customizing-components.md new file mode 100644 index 000000000..cecc40baa --- /dev/null +++ b/guides/plugins/plugins/administration/module-component-management/customizing-components.md @@ -0,0 +1,485 @@ +--- +nav: + title: Customizing components + position: 170 +--- + +# Customizing components + +The Shopware 6 Administration allows you to override and extend components to change its content and its behavior. + +## Prerequisites + +All you need for this guide is a running Shopware 6 instance, the files and preferably a registered module. +Of course, you will have to understand JavaScript, Vue and have a basic familiarity with TwigJS block system, and the templating engine used in the Administration. It is just used for the block extending and overriding. Every other feature of TwigJS is not used in the Administration. +However, that is a prerequisite for Shopware as a whole and will not be taught as part of this documentation. + +## General + +To add new functionality or change the behavior of an existing component, you can either override or extend the component. + +The difference between the two methods is that with `Component.extend()` a new component is created. With `Component.override()`, on the other hand, the previous behavior of the component is simply overwritten. + +## Override a component + +The following example shows how you can override the template of the `sw-text-field` component. + +```JS +// import the new twig-template file +import template from './sw-text-field-new.html.twig'; + +// override the existing component `sw-text-field` by passing the new configuration +Shopware.Component.override('sw-text-field', { + template +}); +``` + +## Extending a component + +To create your custom text-field `sw-custom-field` based on the existing `sw-text-field` you can implement it like the following: + +```JS +// import the custom twig-template file +import template from './sw-custom-field.html.twig'; + +// extend the existing component `sw-text-field` by passing +// a new component name and the new configuration +Shopware.Component.extend('sw-custom-field', 'sw-text-field', { + template +}); +``` + +Now you can render your new component `sw-custom-field` in any template like this: + +```twig + +``` + +## Customize a component template + +To extend a given template you can use the Twig `block` feature. + +Imagine, the component you want to extend/override has the following template: + +```twig +{% block card %} +
+ {% block card_header %} +
+ {{ header }} +
+ {% endblock %} + + {% block card_content %} +
+ {{ content }} +
+ {% endblock %} +
+{% endblock %} +``` + +Maybe you want to replace the markup of the header section and add an extra block to the content. +With the Twig `block` feature you can implement a solution like this: + +```twig +{# override/replace an existing block #} +{% block card_header %} +

+ {{ header }} +

+{% endblock %} + +{% block card_content %} + + {# render the original block #} + {% parent %} + +
+ ... +
+{% endblock %} +``` + +Summarized with the `block` feature you will be able to replace blocks inside a template. +Additionally, you can render the original markup of a block by using `{% parent %}` + +## Extending methods and computed properties + +Sometimes you need to change the logic of a method or a computed property while you are extending/overriding a component. +In the following example we extend the `sw-text-field` component and change the `onInput()` method, which gets called after the value of the input field changes. + +```JS +// extend the existing component `sw-text-field` by passing +// a new component name and the new configuration +Shopware.Component.extend('sw-custom-field', 'sw-text-field', { + + // override the logic of the onInput() method + methods: { + onInput() { + // add your custom logic in here + // ... + } + } +}); +``` + +In the previous example, the inherited logic of `onInput()` will be replaced completely. +But sometimes, you will only be able to add additional logic to the method. You can achieve this by using `this.$super()` call. + +```JS +// extend the existing component `sw-text-field` by passing +// a new component name and the new configuration +Shopware.Component.extend('sw-custom-field', 'sw-text-field', { + + // extend the logic of the onInput() method + methods: { + onInput() { + // call the original implementation of `onInput()` + const superCallResult = this.$super('onInput'); + + // add your custom logic in here + // ... + } + } +}); +``` + +This technique also works for `computed` properties, for example: + +```JS +// extend the existing component `sw-text-field` by passing +// a new component name and the new configuration +Shopware.Component.extend('sw-custom-field', 'sw-text-field', { + + // extend the logic of the computed property `stringRepresentation` + computed: { + stringRepresentation() { + // call the original implementation of `onInput()` + const superCallResult = this.$super('stringRepresentation'); + + // add your custom logic in here + // ... + } + } +}); +``` + +## Real world example for block overriding + +### Finding the block to override + +In this guide we want to change the heading of the Shopware 6 dashboard to be `Welcome to a customized Administration` instead of `Welcome to Shopware 6`. +To do this, we first need to find an appropriate twig block to override. +We don't want to replace too much but also to not override too little of the Administration. +In this case, we only want to override the headline and not links or anything else on the page. +Looking at the twig markup for the dashboard [here](https://github.com/shopware/shopware/blob/trunk/src/Administration/Resources/app/administration/src/module/sw-dashboard/page/sw-dashboard-index/sw-dashboard-index.html.twig), +suggests that we only need to override the twig block with the name `sw_dashboard_index_content_intro_content_headline` to achieve our goal. + +### Preparing the override + +Now that we know where to place our override, we need to decide what to override it with. +In this very simple example it suffices to create a twig file, declare a block with the name we previously found and to insert our new header into the block. + +```text + +{% block sw_dashboard_index_content_intro_content_headline %} +

+ Welcome to a customized component +

+{% endblock %} +``` + +This overrides the entire twig block with our new markup. +However, if we want to retain the original content of the twig block and just add our markup to the existing one, we can do that by including a {% parent %} somewhere in the twig block. +Learn more about the capabilities of twig.js [here](https://github.com/twigjs/twig.js/wiki). + +As you might have noticed the heading we just replaced had a `{ $tc() }` [string interpolation](https://vuejs.org/v2/guide/syntax.html#Text) which is used to make it multilingual. +Learn more about internationalization in the Shopware 6 Administration and about adding your own snippets to the Administration [here](adding-snippets). + +### Applying the override + +Registering the override of the Vue component is done by using the override method of our ComponentFactory. +This could be done in any `.js` file, which then has to be later imported, but we'll place it in `/src/Resources/app/administration/src/sw-dashboard-index-override/index.js`. + +```javascript +import template from './sw-dashboard-index.html.twig'; + +Shopware.Component.override('sw-dashboard-index', { + template +}); +``` + +The first parameter matches the component to override, the second parameter has to be an object containing the actually overridden properties for example, the new twig template extension for this component. + +### Loading the JavaScript File + +The main entry point to customize the Administration via a plugin is the `main.js` file. +It has to be placed into the `/src/Resources/app/administration/src` directory in order to be automatically found by Shopware 6. + +The only thing now left to just add an import for our previously created `./sw-dashboard-index-override/index.js` in the `main.js`: + +```javascript +import './sw-dashboard-index-override/'; +``` + +## Experimental: Composition API extension system + +Shopware 6 is introducing a new way to extend components using the Composition API. This system is currently in an experimental state and is needed for the future migration of components from the Options API to the Composition API. + +### Current status and future plans + +- The existing Options API extension system remains fully supported and functional. +- The new Composition API extension system is introduced as an experimental feature. +- In future versions, components will gradually migrate from Options API to Composition API. +- Plugin developers are encouraged to familiarize themselves with the new system, but should continue using the current Component factory extension system for components written with the Options API. +- For components written with the Composition API, the new extension system should be used. +- In the long term, the Composition API extension system will become the standard way to override components. The Options API extension system will be deprecated and eventually removed when all components are migrated to the Composition API. + +### How it works + +The new extension system introduces two main functions: + +1. `Shopware.Component.createExtendableSetup`: Used within components to make them extendable. This will mainly be used by the core team to make components extendable. +2. `Shopware.Component.overrideComponentSetup`: Used by plugins to override components. + +### Using overrideComponentSetup + +The `overrideComponentSetup` function is a key part of the new Composition API extension system. It allows plugin developers to override or extend the behavior of existing components without directly altering their source code. + +### Basic usage + +```javascript +Shopware.Component.overrideComponentSetup()('componentName', (previousState, props, context) => { + // Your extension logic here + return { + // Return the new or modified properties and methods + }; +}); +``` + +#### Parameters + +1. `componentName`: A string identifying the component you want to override. +2. Callback function: This function receives three arguments: + 1. `previousState`: The current state of the component, including all its reactive properties and methods. + 2. `props`: The props passed to the component. + 3. `context`: The setup context, similar to what you would receive in a standard Vue 3 setup function. + +#### Return value + +The callback function should return an object containing any new or modified properties or methods you want to add or change in the component. + +#### Example: Replacing a Single Property + +```javascript +Shopware.Component.overrideComponentSetup()('sw-product-list', (previousState) => { + const newPageSize = ref(50); + + return { + pageSize: newPageSize // Override the default page size with the new ref + }; +}); +``` + +#### Example: Adding a New Method + +```javascript +Shopware.Component.overrideComponentSetup()('sw-order-list', (previousState) => { + return { + newCustomMethod() { + console.log('This is a new method added to sw-order-list'); + } + }; +}); +``` + +#### Example: Modifying existing data + +```javascript +Shopware.Component.overrideComponentSetup()('sw-customer-list', (previousState) => { + // Add a new column to the list + previousState.columns.push({ property: 'customField', label: 'Custom Field' }); + + return {}; +}); +``` + +#### Example: Overwriting a method + +```javascript +Shopware.Component.overrideComponentSetup()('sw-customer-list', (previousState) => { + // Overwrite the existing method + const newIncrement = () => { + // Able to access the previous method + previousState.increment(); + // Add custom logic + console.log('Incremented by 1'); + }; + + return { + increment: newIncrement, + }; +}); +``` + +#### Example: Accessing props and context + +```javascript +Shopware.Component.overrideComponentSetup()('sw-customer-list', (previousState, props, context) => { + // Access the props + console.log(props); + + // Access the context + console.log(context); + + return {}; +}); +``` + +### Important notes + +1. Type Safety: The system aims to provide type safety. Make sure your IDE is set up to recognize the types from Shopware's type definitions. +2. Reactive Properties: When modifying reactive properties, ensure you maintain their reactivity. Use Vue's reactive utilities when necessary. +3. Multiple Overrides: Multiple plugins can override the same component. Overrides are applied in the order they are registered. +4. Performance: Be mindful of performance implications when adding complex logic to frequently used components. +5. Compatibility: This method is part of the experimental Composition API system. Ensure your plugin clearly states its dependency on this feature. +6. Testing: Thoroughly test your overrides, especially when modifying core component behavior. + +### Example real world usage + +Here is an example of how to create an extendable component and how to override it: + +```javascript +import { defineComponent, reactive } from 'vue'; + +// Original component +const originalComponent = defineComponent({ + template: ` +
+

{{ message }}

+
+ Increment + +

+ {{ countMessage }} +

+ +

+ Notifications are currently: {{ showNotification ? 'enabled' : 'disabled' }} +

+
+
+ `, + props: { + showNotification: { + type: Boolean, + default: false, + }, + }, + setup: (props, context) => Shopware.Component.createExtendableSetup({ + props, + context, + name: 'originalComponent', + }, () => { + const count = ref(0); + const message = 'Hello from Shopware!'; + const countMessage = computed(() => `The current count is: ${count.value}`); + + const increment = () => { + count.value++; + }; + + const privateExample = ref('This is a private property'); + + return { + public: { + count, + message, + countMessage, + increment, + }, + private: { + privateExample, + } + }; + }), +}); + +// Overriding the component with a plugin +Shopware.Component.overrideComponentSetup()('originalComponent', (previousState, props) => { + const newMessage = 'Hello from the plugin!'; + const newCountMessage = computed(() => `The new, amazing count is: ${previousState.count.value}`); + const newIncrement = () => { + previousState.increment(); + + if (props.showNotification) { + Shopware.ServiceContainer.get('notification').dispatch({ + title: 'Incremented!', + message: `The count has been incremented by the user to ${previousState.count.value}!`, + variant: 'success', + }); + } + }; + + return { + message: newMessage, + countMessage: newCountMessage, + increment: newIncrement, + }; +}); +``` + +In this example, `createExtendableSetup` is used to make the `originalComponent` extendable. The `overrideComponentSetup` function is then used to modify the properties of the component. In this case, the message is changed, a new computed property is added, and the increment method is modified to show a notification if the `showNotification` prop is set to `true`. + +### Key differences from Options API extension system + +- Uses Composition API syntax and reactive primitives of Vue 3 instead of Vue 2 options API. +- Extensions are applied using function composition rather than option merging. +- Provides more granular control over what parts of a component can be overridden. +- Only overrides are possible. Extending a component is not supported anymore. This can be done natively with the Composition API. + +### Using TypeScript + +To take full advantage of the Composition API extension system, it is recommended to use TypeScript. This will provide better type safety and autocompletion in your IDE and prevent common errors. + +For adding type safety to props you need to import the type of the component you want to override and use it in the `overrideComponentSetup` function as a generic type: ``. The types for the `previousState` are automatically inferred from the component you are overriding by using the correct component name. + +```typescript +import _InternalTestComponent from 'src/the/path/to/the/exported/component'; + +Shopware.Component.overrideComponentSetup()('_internal_test_compponent', (previousState, props) => { + const newBaseValue = ref(5); + const newMultipliedValue = computed(() => { + // Props are now correctly typed + return newBaseValue.value * props.multiplier!; + }); + + // Previous state is now correctly typed + previousState.baseValue.value = 2; + + return { + baseValue: newBaseValue, + multipliedValue: newMultipliedValue, + }; +}); +``` + +### Accessing private properties + +In some cases, you may need to access private properties of a component. This is not recommended, as it can lead to unexpected behavior and breakages when the component is updated. However, if you need to access private properties for debugging or testing purposes, you can do so using the `_private` property of the `previousState` object where all private properties are stored. + +Note: overriding and accessing private properties has no TS support and is not recommended for production use. + +```javascript +Shopware.Component.overrideComponentSetup()('sw-customer-list', (previousState, props, context) => { + // Access the private properties + console.log(previousState._private.thePrivateProperty); +}); +``` + +## More interesting topics + +- [Customizing templates](writing-templates) +- [Customizing via custom styles](add-custom-styles) +- [Using base components](using-base-components) diff --git a/guides/plugins/plugins/administration/customizing-modules.md b/guides/plugins/plugins/administration/module-component-management/customizing-modules.md similarity index 100% rename from guides/plugins/plugins/administration/customizing-modules.md rename to guides/plugins/plugins/administration/module-component-management/customizing-modules.md diff --git a/guides/plugins/plugins/administration/using-base-components.md b/guides/plugins/plugins/administration/module-component-management/using-base-components.md similarity index 100% rename from guides/plugins/plugins/administration/using-base-components.md rename to guides/plugins/plugins/administration/module-component-management/using-base-components.md diff --git a/guides/plugins/plugins/administration/add-acl-rules.md b/guides/plugins/plugins/administration/permissions-error-handling/add-acl-rules.md similarity index 99% rename from guides/plugins/plugins/administration/add-acl-rules.md rename to guides/plugins/plugins/administration/permissions-error-handling/add-acl-rules.md index f32a579b2..bace31375 100644 --- a/guides/plugins/plugins/administration/add-acl-rules.md +++ b/guides/plugins/plugins/administration/permissions-error-handling/add-acl-rules.md @@ -36,7 +36,7 @@ A distinction is made here between normal `permissions` and `additional_permissi ### Normal permissions -![Permissions GUI](../../../../assets/permissions-gui.png) +![Permissions GUI](../../../../../assets/permissions-gui.png) `permissions`: @@ -61,7 +61,7 @@ For each admin privilege, the needed entity privileges need to be assigned. Depe In addition to the normal `permissions`, which represent CRUD functionality, there are also `additional_permissions`. These are intended for all functions that cannot be represented by CRUD. -![Additional permissions GUI](../../../../assets/additionalPermissions-gui.png) +![Additional permissions GUI](../../../../../assets/additionalPermissions-gui.png) The `additional_permissions` have their own card below the normal permissions grid. An example for `additional_permissions` would be: "clearing the cache". This is an individual action without CRUD functionalities. The key is still used for grouping. Therefore the role can be individual and does not have to follow the scheme. diff --git a/guides/plugins/plugins/administration/add-error-handling.md b/guides/plugins/plugins/administration/permissions-error-handling/add-error-handling.md similarity index 100% rename from guides/plugins/plugins/administration/add-error-handling.md rename to guides/plugins/plugins/administration/permissions-error-handling/add-error-handling.md diff --git a/guides/plugins/plugins/administration/add-custom-route.md b/guides/plugins/plugins/administration/routing-navigation/add-custom-route.md similarity index 100% rename from guides/plugins/plugins/administration/add-custom-route.md rename to guides/plugins/plugins/administration/routing-navigation/add-custom-route.md diff --git a/guides/plugins/plugins/administration/add-menu-entry.md b/guides/plugins/plugins/administration/routing-navigation/add-menu-entry.md similarity index 100% rename from guides/plugins/plugins/administration/add-menu-entry.md rename to guides/plugins/plugins/administration/routing-navigation/add-menu-entry.md diff --git a/guides/plugins/plugins/administration/add-new-tab.md b/guides/plugins/plugins/administration/routing-navigation/add-new-tab.md similarity index 100% rename from guides/plugins/plugins/administration/add-new-tab.md rename to guides/plugins/plugins/administration/routing-navigation/add-new-tab.md diff --git a/guides/plugins/plugins/administration/overriding-routes.md b/guides/plugins/plugins/administration/routing-navigation/overriding-routes.md similarity index 100% rename from guides/plugins/plugins/administration/overriding-routes.md rename to guides/plugins/plugins/administration/routing-navigation/overriding-routes.md diff --git a/guides/plugins/plugins/administration/add-custom-service.md b/guides/plugins/plugins/administration/services-utilities/add-custom-service.md similarity index 100% rename from guides/plugins/plugins/administration/add-custom-service.md rename to guides/plugins/plugins/administration/services-utilities/add-custom-service.md diff --git a/guides/plugins/plugins/administration/add-filter.md b/guides/plugins/plugins/administration/services-utilities/add-filter.md similarity index 100% rename from guides/plugins/plugins/administration/add-filter.md rename to guides/plugins/plugins/administration/services-utilities/add-filter.md diff --git a/guides/plugins/plugins/administration/extending-services.md b/guides/plugins/plugins/administration/services-utilities/extending-services.md similarity index 100% rename from guides/plugins/plugins/administration/extending-services.md rename to guides/plugins/plugins/administration/services-utilities/extending-services.md diff --git a/guides/plugins/plugins/administration/injecting-services.md b/guides/plugins/plugins/administration/services-utilities/injecting-services.md similarity index 100% rename from guides/plugins/plugins/administration/injecting-services.md rename to guides/plugins/plugins/administration/services-utilities/injecting-services.md diff --git a/guides/plugins/plugins/administration/the-sanitizer-helper.md b/guides/plugins/plugins/administration/services-utilities/the-sanitizer-helper.md similarity index 100% rename from guides/plugins/plugins/administration/the-sanitizer-helper.md rename to guides/plugins/plugins/administration/services-utilities/the-sanitizer-helper.md diff --git a/guides/plugins/plugins/administration/using-filter.md b/guides/plugins/plugins/administration/services-utilities/using-filter.md similarity index 100% rename from guides/plugins/plugins/administration/using-filter.md rename to guides/plugins/plugins/administration/services-utilities/using-filter.md diff --git a/guides/plugins/plugins/administration/using-utils.md b/guides/plugins/plugins/administration/services-utilities/using-utils.md similarity index 100% rename from guides/plugins/plugins/administration/using-utils.md rename to guides/plugins/plugins/administration/services-utilities/using-utils.md diff --git a/guides/plugins/plugins/administration/system-updates/vite.md b/guides/plugins/plugins/administration/system-updates/vite.md new file mode 100644 index 000000000..a4dc20c7e --- /dev/null +++ b/guides/plugins/plugins/administration/system-updates/vite.md @@ -0,0 +1,119 @@ +--- +nav: + title: Changing from Webpack to Vite + position: 260 +--- + +# Future Development Roadmap: Changing from Webpack to Vite + +> **Note:** The information provided in this article, including timelines and specific implementations, is subject to change. +> This document serves as a general guideline for our development direction. + +## Introduction + +We are planning substantial changes to the way we build our Vue.js application. +The current Webpack build system has been in place for quite some time now, but like everything in tech, it becomes outdated sooner than later. Additionally to Webpack being slow and outdated, we identified a security risk for the future of our application. Many Webpack maintainers have moved on to other projects. Therefore, the Webpack project no longer receives significant updates. The same applies to the Webpack loaders we currently use. + +## Introducing Vite + +The Vue.js ecosystem has built its own bundler: Vite. Vite is fast, easier to configure and the new standard for Vue.js applications. That's why we decided to switch to Vite with Shopware 6.7. + +## Consequences for extensions + +For apps there are no consequences as your build process is already decoupled from Shopware. For plugins you only need to get active if you currently extend the webpack config by providing your own `webpack.config.js` file. + +## Implementation details + +In this section we'll document the implementation details of the new Vite setup. + +### Feature flag + +The system is already in place and can be tested by activating the feature flag: `ADMIN_VITE`. + +### Bundle information + +The information about all active bundles/plugins is written to `/var/plugins.json` by the `Shopware\Core\Framework\Plugin\Command\BundleDumpCommand`. This command can be triggered standalone by running `php bin/console bundle:dump`. It is also part of the composer commands `build:js:admin`, `build:js:storefront`, `watch:admin` and `watch:storefront`. This file is used to load all the Shopware Bundles and custom plugins. + +### Building the Shopware Administration + +The command responsible for building the Shopware Administration with all extensions remains `composer build:js:admin`. + +### Building the core + +The Vite config located under `/src/Administration/Resources/app/administration/vite.config.mts` is only responsible for the core without extensions. Currently there are a few file duplications because Vite requires different module loading order. You can recognize these files, they look like this: `*.vite.ts`. So for example the entry file `/src/Administration/Resources/app/administration/src/index.vite.ts`. + +### Building extensions + +The script responsible for building all extensions is located at `/src/Administration/Resources/app/administration/build/plugins.vite.ts`. This script uses the JS API of Vite to build all extensions. As mentioned above, it's still part of the `composer build:js:admin` command and needs no manual execution. + +The script will do the following: + +1. Get all bundles/plugins from the `/var/plugins.json` +2. Call `build` from Vite for each plugin +3. The `build` function of Vite will automatically load `vite.config` files from the path of the entry file. + +### Dev mode/HMR server + +The command responsible for serving the application in dev mode (HMR server) is still `composer watch:admin`. For the core it's just going to take the `vite.config.mts` again and this time the `plugins.vite.ts` script will call `createServer` for each plugin. + +### Loading Vite assets + +Once built the right assets need to be loaded somehow into the administration. For the core we use the `pentatrion_vite` Symfony bundle. Loading the correct file(s) based on the `entrypoints.json` file generated by its counterpart `vite-plugin-symfony`. For bundles and plugins the boot process inside the `application.ts` will load and inject the entry files based on the environment. + +Production build: + +- Information is taken from the `/api/_info/config` call + +Dev mode/HMR server: + +- Information is served by our own Vite plugin `shopware-vite-plugin-serve-multiple-static` in form of the `sw-plugin-dev.json` file requested by the `application.ts` + +## Vite plugins + +To accomplish all this, we created a few Vite plugins and in this section we'll take the time to explain what they do. All our Vite plugin names are prefixed with `shopware-vite-plugin-`. I'll leave this out of the headlines for better readability. + +### asset-path + +This plugin manipulates the chunk loading function of Vite, to prepend the `window.__sw__.assetPath` to the chunk path. This is needed for cluster setups, serving the assets from a S3 bucket. + +### static-assets + +Copies static admin assets from `static` to the output directory so they can get served. + +### serve-multiple-static + +Serves static assets in dev mode (HMR server). + +### vue-globals + +Replacing all Vue imports in bundles/plugins to destructure from `Shopware.Vue`. This solves the problem of having multiple Vue instances. It does this by creating a temporary file exporting the Shopware.Vue and adding an alias to point every Vue import to that temporary file. This way it will result in bundled code like this: + +From this: + +```vue +// From this + + +// To this + +``` + +### override-component + +Registering `*.override.vue` files automatically. It will search for all files matching the override pattern and automatically import them into the bundle/plugin entry file. Additionally, these imports will be registered as override components by calling `Shopware.Component.registerOverrideComponent`. This will make sure that all overrides are loaded at any time as soon as the bundle/plugin script is injected. To learn more about the new overrides take a look at the Vue native docs right next to this file. + +### twigjs + +Transforming all `*.html.twig` files in a way that they can be loaded by Vite. + +## HMR reloading + +A quick note on HMR (Hot Module Replacement). Vite is only capable of reloading `*.vue` files. This means that we can only leverage the HMR by the time we transitioned everything to SFC (Single File Components) but once we do the Vite setup will be able to distinguish between changes in a plugin or the core. + +## Performance + +Vite is able to build the core Administration in ~18s on my system. This is a saving of over 50% compared to Webpack. In dev mode it's similar but not directly comparable. The Vite dev server starts instantly and moves the loading time to the first request. Webpack on the other hand compiles a long time upfront until the server is ready. diff --git a/guides/plugins/plugins/administration/system-updates/vue-native.md b/guides/plugins/plugins/administration/system-updates/vue-native.md new file mode 100644 index 000000000..99f2594b4 --- /dev/null +++ b/guides/plugins/plugins/administration/system-updates/vue-native.md @@ -0,0 +1,340 @@ +--- +nav: + title: Native Vue + position: 260 +--- + +# Future Development Roadmap: Moving Towards Vue Native + +> **Note:** The information provided in this article, including timelines and specific implementations, is subject to change. +> This document serves as a general guideline for our development direction. + +## Introduction + +We are planning a significant shift in our development approach, moving towards a more native Vue.js implementation. +This document outlines the reasons for this change and provides an overview of our upgrade path. + +## Current status + +To better understand the changes described in this article, let's recap the current status. +The Shopware 6 Administration is built around Vue.js with several custom systems on top to allow for extensions. + +### Custom component registration + +```javascript +Shopware.Component.register('sw-component', { + template, + + //... +}); +``` + +### Custom templates with Twig.Js + +```html +{% block sw-component %} + +{% endblock %} +``` + +## Why Go Native? + +Our transition to a more native Vue.js approach is driven by several key factors: + +1. **Improved Developer Experience** + - Devtool enhancements + - Easier maintenance + +2. **Future-Proofing** + - Aligning with Vue 3 and potential future versions + - Preparing for upcoming industry standards + +3. **Performance Optimization** + - Leveraging native Vue.js capabilities for better performance + +## Major Changes + +### 1. Moving from Options API to Composition API + +#### Why Make This Change? + +We aim to better align with Vue's ecosystem, to minimize the amount of specifications new Developers need to learn. +The Composition API has become the new standard for Vue's documentation and projects all over Github. +Renowned libraries like `vue-i18n` are dropping support of the Options API, as seen in their [migration guide](https://vue-i18n.intlify.dev/guide/migration/vue3#summary), and we expect similar transitions from other tools in the ecosystem. +This also aligns with Vue's best practices, as highlighted in the official [Composition API FAQ](https://vuejs.org/guide/extras/composition-api-faq.html#why-composition-api). + +#### What Will Change? + +We will gradually transform our components from Options API to Composition API. Together with native blocks, this builds the foundation to use Single File Components (SFC). +The transformation will be stretched over multiple major versions to offer enough time for all of us to adapt. Take a look at the estimated timeline below. + +#### Upgrade Path + +| Shopware Version | Options API | Composition API | +|:----------------:|---------------------------------|------------------------------| +| 6.7 | Standard | Experimental | +| 6.8 | Still supported for extensions* | Standard for Core components | +| 6.9 | Removed completely | Standard | + +*Extensions still can register components using the Options API; overwriting Core components needs the Composition API. + +### 2. TwigJS to Native Blocks + +#### Why Make This Change? + +Vue has no native support for blocks like in Twig.js. Vue has slots, but slots don't work like blocks. +Recently, we accomplished the unthinkable and found a way to implement blocks with native Vue components. +This will allow us to finally use SFC and keep the extendability of Twig.js. +Lowering the learning curve, as the Twig.js syntax is especially unfamiliar to Vue developers. +Standard tooling like VSCode, ESLint, and Prettier will work out of the box. + +#### What Will Change? + +We will gradually transform all component templates from external `*.html.twig` files with Twig.Js into `.vue` files using the native block implementation. + +#### Upgrade Path + +| Shopware Version | Twig.Js | Native blocks | +|:----------------:|---------------------------------|------------------------------| +| 6.7 | Standard | Experimental | +| 6.8 | Still supported for extensions* | Standard for Core components | +| 6.9 | Removed completely | Standard | + +*Extensions still can register components using Twig.Js templates; overwriting Core blocks needs the native block implementation. + +### 3. Vuex to Pinia + +#### Why Make This Change? + +Vuex has been the default State management for Vue 2. For Vue 3 Pinia took it's place. + +#### What Will Change? + +We will move all core Vuex states to Pinia stores. The public API will change from `Shopware.State` to `Shopware.Store`. + +#### Upgrade Path + +| Shopware Version | Vuex | Pinia | +|:----------------:|---------------------------------|------------------------------| +| 6.7 | Still supported for extensions* | Standard for Core components | +| 6.8 | Removed completely | Standard | + +*Extensions still can register Vuex states; Accessing core stores is done via Pinia + +## Example: Component Evolution + +Now let's take a look how core and extension components will evolve. + +### Shopware 6.7 + +First we start with the current status which is still compatible with Shopware 6.7. + +#### Core component + +In the core we register a component via `Shopware.Component.register`. + +```javascript +Shopware.Component.register('sw-text-field', { + template: ` + {% block sw-text-field %} + + {% endblock %} + `, + + data() { + return { + value: null, + } + }, + + methods: { + onChange() { + this.$emit('update:value', this.value); + } + }, +}); +``` + +#### Extension override + +The extension overrides the component via `Shopware.Component.override`. + +```javascript +Shopware.Component.override('sw-text-field', { + template: ` + {% block sw-text-field %} + {% parent %} + + {{ helpText }} + {% endblock %} + `, + + props: { + helpText: { + type: String, + required: false, + } + } +}) +``` + +#### Extension new component + +The extension adds additional component via `Shopware.Component.register`. + +```javascript +Shopware.Component.register('your-crazy-ai-field', { + template: ` + {% block your-crazy-ai-field %} + {# ... #} + {% endblock %} + `, + + // Options API implementation +}) +``` + +### Shopware 6.8 + +With Shopware 6.8 the core uses single file components with the composition API. + +#### Core component + +The core component is added via a single file component `*.vue` file. + +```vue + + + +``` + +#### Extension override + +For overrides we created a new convention. They must match the `*.override.vue` pattern. +`*.override.vue` files will be loaded automatically in your main entry file. + +```vue + + + +``` + +#### Extension new component + +```javascript + +// For this you would also have the option to use a `*.vue` file but you don't have to +Shopware.Component.register('your-crazy-ai-field', { + template: ` + {% block your-crazy-ai-field %} + {# ... #} + {% endblock %} + `, + + // Options API implementation +}) +``` + +### Shopware 6.9 + +The only difference for 6.9 is that you can no longer register new components via `Shopware.Component.register`. + +## FAQ + +**Will existing extensions built with Options API continue to work in Shopware 6.8?** + +When you only use `Shopware.Component.register` yes. If you also use `Shopware.Component.extend/ override` you need to use the composition API extension approach for that. + +**How can I prepare my development team for the transition to Composition API?** + +I would recommend building a simple Vue application using the Composition API. You can do so by following [official guides](https://vuejs.org/guide/extras/composition-api-faq.html). + +**What advantages does the native block implementation offer over the current Twig.js system?** + +It works with native Vue.Js components, therefore is compatible with default tooling. + +**Can I mix Composition API and Options API components during the transition period?** + +Yes as long as you stick to the limitations from the upgrade paths. + +**How will the migration from Twig.js templates to .vue files affect my existing component overrides?** + +You need to migrate all your overrides with Shopware 6.8. + +**What tools or resources will be available to help migrate existing components?** + +We'll try to provide a code mod to transition your components into SFC. This will not work for all edge cases, so you need to manually check and transition them. + +**Will there be any performance impact during the transition period when both systems are supported?** + +During our tests we didn't experience any performance issues. + +**How does the new `Shopware.Component.createExtendableSetup` function work with TypeScript?** + +It has built in TypeScript support. + +**What happens to existing extensions using Twig.js templates after version 6.9?** + +They will stop working with Shopware version 6.9. + +**Can I start using the native blocks and Composition API in my extensions before version 6.8?** + +Yes! You can add new components using SFC and native blocks. But you can't extend core components using the old systems or vise versa. + +**Which extensions are affected by these changes?** + +- Apps aren't affected at all +- Plugins need to respect the discussed changes diff --git a/guides/plugins/plugins/administration/add-custom-styles.md b/guides/plugins/plugins/administration/templates-styling/add-custom-styles.md similarity index 100% rename from guides/plugins/plugins/administration/add-custom-styles.md rename to guides/plugins/plugins/administration/templates-styling/add-custom-styles.md diff --git a/guides/plugins/plugins/administration/adding-snippets.md b/guides/plugins/plugins/administration/templates-styling/adding-snippets.md similarity index 100% rename from guides/plugins/plugins/administration/adding-snippets.md rename to guides/plugins/plugins/administration/templates-styling/adding-snippets.md diff --git a/guides/plugins/plugins/administration/using-assets.md b/guides/plugins/plugins/administration/templates-styling/using-assets.md similarity index 99% rename from guides/plugins/plugins/administration/using-assets.md rename to guides/plugins/plugins/administration/templates-styling/using-assets.md index b10e92c75..cce52c4c5 100644 --- a/guides/plugins/plugins/administration/using-assets.md +++ b/guides/plugins/plugins/administration/templates-styling/using-assets.md @@ -65,7 +65,7 @@ Note that [Vue filters](https://vuejs.org/v2/guide/filters.html) are no longer s Create a computed component to make them easy to use in your template. -```js +```javascript computed: { assetFilter() { return Shopware.Filter.getByName('asset'); diff --git a/guides/plugins/plugins/administration/writing-templates.md b/guides/plugins/plugins/administration/templates-styling/writing-templates.md similarity index 100% rename from guides/plugins/plugins/administration/writing-templates.md rename to guides/plugins/plugins/administration/templates-styling/writing-templates.md diff --git a/guides/plugins/plugins/administration/adding-responsive-behavior.md b/guides/plugins/plugins/administration/ui-ux/adding-responsive-behavior.md similarity index 100% rename from guides/plugins/plugins/administration/adding-responsive-behavior.md rename to guides/plugins/plugins/administration/ui-ux/adding-responsive-behavior.md diff --git a/guides/plugins/plugins/checkout/cart/add-cart-validator.md b/guides/plugins/plugins/checkout/cart/add-cart-validator.md index a75813d5d..940c78b43 100644 --- a/guides/plugins/plugins/checkout/cart/add-cart-validator.md +++ b/guides/plugins/plugins/checkout/cart/add-cart-validator.md @@ -182,7 +182,7 @@ You've defined the error key to be `custom-line-item-blocked` in your custom err Now let's have a look at an example snippet file: -```js +```javascript // /src/Resources/snippet/en\_GB/example.en-GB.json { "checkout": { diff --git a/guides/plugins/plugins/content/cms/add-cms-block.md b/guides/plugins/plugins/content/cms/add-cms-block.md index d1dc8cc8d..21164e6d2 100644 --- a/guides/plugins/plugins/content/cms/add-cms-block.md +++ b/guides/plugins/plugins/content/cms/add-cms-block.md @@ -198,7 +198,7 @@ The preview element doesn't have to deal with mobile viewports or anything alike Also, you need to create a computed component to access the asset filter in your template. -```js +```javascript // /src/Resources/app/administration/src/module/sw-cms/blocks/text-image/my-image-text-reversed/preview/index.js computed: { assetFilter() { diff --git a/guides/plugins/plugins/framework/data-handling/add-custom-complex-data.md b/guides/plugins/plugins/framework/data-handling/add-custom-complex-data.md index 401cc01f7..0e67d7afa 100644 --- a/guides/plugins/plugins/framework/data-handling/add-custom-complex-data.md +++ b/guides/plugins/plugins/framework/data-handling/add-custom-complex-data.md @@ -193,6 +193,7 @@ The entity class itself is a simple key-value object, like a struct, which conta ::: warning The properties of your entity class have to be at least `protected`, otherwise the data abstraction layer won't be able to set the values. +For the same reason `readonly` properties are not allowed. This holds true not just for `Entity` classes, but for all classes that extend the generic `Struct` class. ::: ```php diff --git a/guides/plugins/plugins/framework/event/finding-events.md b/guides/plugins/plugins/framework/event/finding-events.md index ed4e611f9..dd4c37810 100644 --- a/guides/plugins/plugins/framework/event/finding-events.md +++ b/guides/plugins/plugins/framework/event/finding-events.md @@ -111,6 +111,7 @@ Use one of the following search terms: - `extends NestedEvent`: This way you will find the events themselves. - `extends Event`: This way you will find the events themselves. +- `implements ShopwareEvent`: This way you will find the events themselves. - `->dispatch`: Here you will find all the occurrences where the events are actually being fired. ### Looking at the service definition @@ -201,6 +202,39 @@ Finding those events can be done by searching for the term `CriteriaEvent`. Those "criteria events" are not generated automatically and therefore it is not guaranteed to exist for a given entity. ::: +#### Route Events + +Symfony provides some general [kernel level routing events](https://symfony.com/doc/current/reference/events.html#kernel-events), e.g `kernel.request` or `kernel.response`. +However, those events are thrown on every route, so it's too generic when you only want to react on a specific route. +Therefore, we have added fine-grained route events that are thrown for every route: +| Event name | Scope | Event Type | Description | +|------------|-------|------------|-------------| +| `{route}.request` | Global | `Symfony\Component\HttpKernel\Event\RequestEvent` | Route specific alias for symfony's `kernel.request` event. | +| `{route}.response` | Global | `Symfony\Component\HttpKernel\Event\ResponseEvent` | Route specific alias for symfony's `kernel.response` event. For storefront routes this contains the already rendered template, for store-api routes this contains the already encoded JSON | +| `{route}.render` | Storefront | `Shopware\Storefront\Event\StorefrontRenderEvent` | Thrown before twig rendering in the storefront. | +| `{route}.encode` | Store-API | `Symfony\Component\HttpKernel\Event\ResponseEvent` | Thrown before encoding the API response to JSON, allowing easy manipulation of the returned data. **Note:** This was only introduced in 6.6.11.0 | +| `{route}.controller` | Global | `\Symfony\Component\HttpKernel\Event\ControllerEvent` | Route specific alias for symfony's `kernel.controller` event. **Note:** This was only introduced in 6.6.11.0 | + +To subscribe to a specific event, replace the `{route}` placeholder with the [actual symfony route name](https://symfony.com/doc/current/routing.html), e.g. `store-api.product.listing`. + +```php +public static function getSubscribedEvents(): array +{ + return [ + 'store-api.product.listing.request' => 'onListingRequest', + 'store-api.product.listing.encode' => 'onListingEncode' + ]; +} + +public function onListingRequest(RequestEvent $event): void +{ +} + +public function onListingEncode(ResponseEvent $event): void +{ +} +``` + #### Business events Business events are fired everytime an important business / ecommerce action occurred, such as "A customer registered" or "An order was placed". diff --git a/guides/plugins/plugins/framework/flow/add-flow-builder-action.md b/guides/plugins/plugins/framework/flow/add-flow-builder-action.md index b20b57483..bfc7f40e3 100644 --- a/guides/plugins/plugins/framework/flow/add-flow-builder-action.md +++ b/guides/plugins/plugins/framework/flow/add-flow-builder-action.md @@ -38,7 +38,9 @@ To create a custom flow action, firstly you have to make a plugin and install it /src/Core/Content/Flow/Dispatching/Action/CreateTagAction.php ... @@ -183,7 +185,7 @@ Here, the action name is empty as the action name snippet is not yet defined. Make the `CreateTagAction` available for all events related to Order and Customer. -```PHP +```php // /src/Core/Content/Flow/Dispatching/Action/CreateTagAction.php ... @@ -201,7 +203,7 @@ Make the `CreateTagAction` available for all events related to Order and Custome - Event must implement the `TagAware` -```PHP +```php // /src/Core/Content/Flow/Subscriber/BusinessEventCollectorSubscriber.php /src/Core/Content/Flow/Dispatching/Action/CreateTagAction.php ... diff --git a/guides/plugins/plugins/framework/flow/add-flow-builder-trigger.md b/guides/plugins/plugins/framework/flow/add-flow-builder-trigger.md index 567f5bc20..0d68c71d9 100644 --- a/guides/plugins/plugins/framework/flow/add-flow-builder-trigger.md +++ b/guides/plugins/plugins/framework/flow/add-flow-builder-trigger.md @@ -281,6 +281,7 @@ class ExampleEvent extends Event implements CustomExampleDataAware Aware: ```php +#[IsFlowEventAware] interface CustomExampleDataAware extends FlowEventAware { public const CUSTOM_EXAMPLE_DATA = 'customExampleData'; diff --git a/guides/plugins/plugins/framework/store-api/add-store-api-route.md b/guides/plugins/plugins/framework/store-api/add-store-api-route.md index 3d2c2a9f6..ceee65e48 100644 --- a/guides/plugins/plugins/framework/store-api/add-store-api-route.md +++ b/guides/plugins/plugins/framework/store-api/add-store-api-route.md @@ -163,7 +163,7 @@ $ ./bin/console debug:router store-api.example.search To add the route to the Swagger page, a JSON file is needed in a specific [format](https://swagger.io/specification/#paths-object). It contains information about the paths, methods, parameters, and more. You must place the JSON file in `/src/Resources/Schema/StoreApi/` so the shopware internal OpenApi3Generator can find it (for Admin API endpoints, use `AdminApi`). -```js +```javascript // /src/Resources/Schema/StoreApi/example.json { "openapi": "3.0.0", diff --git a/guides/plugins/plugins/plugin-base-guide.md b/guides/plugins/plugins/plugin-base-guide.md index 4ff2d8ed3..0f1fbd3ff 100644 --- a/guides/plugins/plugins/plugin-base-guide.md +++ b/guides/plugins/plugins/plugin-base-guide.md @@ -96,7 +96,7 @@ and the `require` field must include at least `shopware/core`, to check for comp Here's an example `composer.json` for this guide, which will do the trick: -```js +```javascript // /composer.json { "name": "swag/basic-example", diff --git a/guides/plugins/plugins/plugin-fundamentals/add-plugin-dependencies.md b/guides/plugins/plugins/plugin-fundamentals/add-plugin-dependencies.md index 9e9029305..ea9acf422 100644 --- a/guides/plugins/plugins/plugin-fundamentals/add-plugin-dependencies.md +++ b/guides/plugins/plugins/plugin-fundamentals/add-plugin-dependencies.md @@ -30,7 +30,7 @@ Important to note is the `name` as well as the `version` mentioned here, the res In order to require the `SwagBasicExample` plugin now, you simply have to add these two information to your own `composer.json` as a key value pair: -```js +```javascript // /composer.json { "name": "swag/plugin-dependency", diff --git a/guides/plugins/plugins/plugin-fundamentals/add-scheduled-task.md b/guides/plugins/plugins/plugin-fundamentals/add-scheduled-task.md index 6b6b48a5d..8a4d53825 100644 --- a/guides/plugins/plugins/plugin-fundamentals/add-scheduled-task.md +++ b/guides/plugins/plugins/plugin-fundamentals/add-scheduled-task.md @@ -117,6 +117,8 @@ In order to properly test your scheduled task, you first have to run the command Now you still need to run the command `bin/console messenger:consume` to actually execute the dispatched messages. Make sure, that the `status` of your scheduled task is set to `scheduled` in the `scheduled_task` table, otherwise it won't be executed. This is not necessary, when you're using the admin worker. + + ## More interesting topics * [Adding a custom command](add-custom-commands) diff --git a/guides/plugins/themes/add-theme-inheritance-without-resources.md b/guides/plugins/themes/add-theme-inheritance-without-resources.md index 1172a64bd..2d5108f72 100644 --- a/guides/plugins/themes/add-theme-inheritance-without-resources.md +++ b/guides/plugins/themes/add-theme-inheritance-without-resources.md @@ -15,7 +15,7 @@ The Shopware default theme is using [Bootstrap](https://getbootstrap.com/) with If you want to build your theme only upon the Bootstrap SCSS you can use the `@StorefrontBootstrap` placeholder instead of the `@Storefront` bundle in the `style` section of your `theme.json`. This gives you the ability to use the Bootstrap SCSS without the Shopware Storefront "skin". Therefore all the SCSS from `src/Storefront/Resources/app/storefront/src/scss/skin` will not be available in your theme. -```js +```javascript // /src/Resources/theme.json { ... diff --git a/guides/plugins/themes/add-theme-inheritance.md b/guides/plugins/themes/add-theme-inheritance.md index 3653c4de8..817439460 100644 --- a/guides/plugins/themes/add-theme-inheritance.md +++ b/guides/plugins/themes/add-theme-inheritance.md @@ -27,7 +27,7 @@ To set up the inheritance we need to edit the theme configuration file called `t The content of the `theme.json` file looks like this: -```js +```javascript // /src/Resources/theme.json { "name": "SwagBasicExampleThemeExtend", @@ -59,7 +59,7 @@ Now it is easy to see how we can inherit from our base theme `SwagBasicExampleTh Here is an example: -```js +```javascript // /src/Resources/theme.json { "name": "SwagBasicExampleThemeExtend", diff --git a/guides/plugins/themes/override-bootstrap-variables-in-a-theme.md b/guides/plugins/themes/override-bootstrap-variables-in-a-theme.md index fca843d9f..d8b6a5a0f 100644 --- a/guides/plugins/themes/override-bootstrap-variables-in-a-theme.md +++ b/guides/plugins/themes/override-bootstrap-variables-in-a-theme.md @@ -29,7 +29,7 @@ To be able to override Bootstrap variables there is an additional SCSS entry poi This entry point is called `overrides.scss`: -```js +```javascript // /src/Resources/theme.json { "name": "SwagBasicExampleTheme", diff --git a/guides/plugins/themes/theme-configuration.md b/guides/plugins/themes/theme-configuration.md index 15839b0f3..4f543fced 100644 --- a/guides/plugins/themes/theme-configuration.md +++ b/guides/plugins/themes/theme-configuration.md @@ -25,7 +25,7 @@ This guide is built upon the guide on creating a first theme: The theme configuration for a theme is located in the `theme.json` file `/src/Resources` folder. Open up the `/src/Resources/theme.json` file with your favorite code-editor. The configuration looks like this. -```js +```javascript // /src/Resources/theme.json { "name": "SwagBasicExampleTheme", @@ -66,7 +66,7 @@ If you make changes or additions to the `theme.json` file, you must then execute Let's have a closer look at each section. -```js +```javascript // /src/Resources/theme.json { "name": "SwagBasicExampleTheme", @@ -83,7 +83,7 @@ Here change the `name` of your theme and the `author`. The `description` section The `views` section controls the template inheritance. This will be covered in the [Theme inheritance](add-theme-inheritance) guide. -```js +```javascript // /src/Resources/theme.json { ... @@ -98,7 +98,7 @@ The `views` section controls the template inheritance. This will be covered in t The `previewMedia` field provides a path `app/storefront/dist/assets/defaultThemePreview.jpg` to an image file that is relative to the root directory of the theme. It serves as a visual preview of the theme. This preview image is typically displayed within the Shopware administration interface or theme marketplace as a thumbnail or preview of the theme's appearance to give users an idea of how the theme will appear on their storefront before they activate it. -```js +```javascript // /src/Resources/theme.json { ... @@ -109,7 +109,7 @@ The `previewMedia` field provides a path `app/storefront/dist/assets/defaultThem The `style` section determines the order of the CSS compilation. In the `/app/storefront/src/scss/base.scss` file you can apply your changes you want to make to the `@Storefront` standard styles or add other styles you need. The `/app/storefront/src/scss/overrides.scss` file is used for a special case. Maybe you need to override some defined `variables` or `functions` defined by Shopware or Bootstrap, you can implement your changes here. Checkout the [Override bootstrap variables in a theme](override-bootstrap-variables-in-a-theme) guide for further information. -```js +```javascript // /src/Resources/theme.json { ... @@ -126,7 +126,7 @@ The `style` section determines the order of the CSS compilation. In the `/app/storefront/src/assets` folder. Checkout the [Add assets to theme](add-assets-to-theme) guide for further information. -```js +```javascript // /src/Resources/theme.json { ... @@ -139,7 +139,7 @@ The `asset` option you can configure your paths to your assets like images, font If you need the assets from the default storefront theme for your custom theme, just add `@Storefront` as asset path -```js +```javascript // /src/Resources/theme.json { ... @@ -155,7 +155,7 @@ If you need the assets from the default storefront theme for your custom theme, One of the benefits of creating a theme is that you can overwrite the theme configuration of the default theme or add your own configurations. -```js +```javascript // /src/Resources/theme.json { ... @@ -202,7 +202,7 @@ You can use different field types in your theme manager: A text field example: -```js +```javascript // /src/Resources/theme.json { ... @@ -224,7 +224,7 @@ A text field example: A number field example: -```js +```javascript // /src/Resources/theme.json { ... @@ -251,7 +251,7 @@ A number field example: Two boolean field examples: -```js +```javascript // /src/Resources/theme.json { ... @@ -273,7 +273,7 @@ Two boolean field examples: or -```js +```javascript // /src/Resources/theme.json { ... @@ -297,7 +297,7 @@ or A custom single-select field example -```js +```javascript // /src/Resources/theme.json { "name": "Just another theme", @@ -388,7 +388,7 @@ A custom single-select field example A custom multi-select field example -```js +```javascript // /src/Resources/theme.json { "name": "Just another theme", @@ -495,7 +495,7 @@ You can use tabs, blocks and sections to structure and group the config options. In the picture above are four tabs. In the "Colours" tab there is one block "Theme colours" which contains two sections named "Important colors" and "Other". You can define the block and section individually for each item. Example: -```js +```javascript // /src/Resources/theme.json { "name": "Just another theme", @@ -524,7 +524,7 @@ The tab and section property is not required. You can extend the config to add translated labels for the tabs, blocks and sections: -```js +```javascript // /src/Resources/theme.json { "name": "Just another theme", @@ -577,7 +577,7 @@ You can extend the config to add translated labels for the tabs, blocks and sect The `configInheritance` option lets you configure additional themes from which your theme will inherit its fields configuration and snippets. Every theme will always inherit the fields from the `Storefront` standard theme. With this option you can add additional other themes. For example, you can have a basic theme for your corporate design and special themes for different sales channels with specific changes only needed for a single sales channel. -```js +```javascript // /src/Resources/theme.json { ... diff --git a/guides/plugins/themes/theme-inheritance-configuration.md b/guides/plugins/themes/theme-inheritance-configuration.md index 75618a7c6..3f4b72153 100644 --- a/guides/plugins/themes/theme-inheritance-configuration.md +++ b/guides/plugins/themes/theme-inheritance-configuration.md @@ -27,7 +27,7 @@ Create the two themes like described in [Theme inheritance](./add-theme-inherita Add some configuration fields you need in your basic theme inside the `theme.json` of the `SwagBasicExampleTheme` -```js +```javascript // /src/Resources/theme.json { "name": "SwagBasicExampleTheme", @@ -88,7 +88,7 @@ Add some configuration fields you need in your basic theme inside the `theme.jso Add configurations to your extended theme -```js +```javascript // /src/Resources/theme.json { "name": "SwagBasicExampleThemeExtend", diff --git a/products/digital-sales-rooms/best-practices/app-deployment/aws.md b/products/digital-sales-rooms/best-practices/app-deployment/aws.md new file mode 100644 index 000000000..c29da5bc0 --- /dev/null +++ b/products/digital-sales-rooms/best-practices/app-deployment/aws.md @@ -0,0 +1,35 @@ +--- +nav: + title: AWS + position: 10 + +--- + +# Deploy with AWS Amplify + +In this chapter, you will learn how to deploy the frontend source code to [AWS Amplify](https://aws.amazon.com/amplify/). + +## Prerequisites + +* Register an AWS account. +* Clone the frontend source code and push it to your GitHub repository. + * Download the plugin zip. After extracting it, you will find it inside `/templates/dsr-frontends`. +* Push source code to your Git repository. + +## Deploy + +* Login to the AWS Amplify Hosting Console. +* Create a new app in AWS Amplify. +* Select and authorize access to your Git repository provider and select the main branch (it will auto deploy when there are some changes in the main branch). +* Choose a name for your app and make sure build settings are auto-detected. +* Set Environment variables under the Advanced Settings section. + * Add `SHOPWARE_STORE_API`, `SHOPWARE_ADMIN_API`, `SHOPWARE_STORE_API_ACCESS_TOKEN`, `SHOPWARE_STOREFRONT_URL`, `ORIGIN` variables with appropriate values. +* Confirm configuration and click on "Save and Deploy". + +## Custom domain + +After deploying your code to AWS Amplify, you may wish to point custom domains (or subdomains) to your site. AWS has an [instruction](https://docs.aws.amazon.com/amplify/latest/userguide/custom-domains.html). + +## Configure sales channel domain + +Your website is ready, and you should have a frontend app domain. Please use the current domain to configure [sales channel domain](../../configuration/domain-config.md). diff --git a/products/digital-sales-rooms/best-practices/app-deployment/cloudflare.md b/products/digital-sales-rooms/best-practices/app-deployment/cloudflare.md index 67db36e2c..54ff963ee 100644 --- a/products/digital-sales-rooms/best-practices/app-deployment/cloudflare.md +++ b/products/digital-sales-rooms/best-practices/app-deployment/cloudflare.md @@ -1,7 +1,7 @@ --- nav: title: Cloudflare - position: 10 + position: 20 --- @@ -49,7 +49,7 @@ wrangler pages deploy dist/ * In GitHub Secrets, add `CLOUDFLARE_API_TOKEN` with API token value. * [Create an API token](https://developers.cloudflare.com/fundamentals/api/get-started/create-token/) in the Cloudflare dashboard with the "Cloudflare Pages — Edit" permission. -* In GitHub environment variables, create new environment named `production`. Add `SHOPWARE_ENDPOINT` and `SHOPWARE_ACCESS_TOKEN` variables with appropriate values. +* In GitHub environment variables, create new environment named `production`. Add `SHOPWARE_STORE_API`, `SHOPWARE_ADMIN_API`, `SHOPWARE_STORE_API_ACCESS_TOKEN`, `SHOPWARE_STOREFRONT_URL`, `ORIGIN` variables with appropriate values. * Besides `production`, we can add new values for the same variable names in multiple environments such as `development`, `staging`. ### Setup pipeline @@ -95,8 +95,12 @@ jobs: - name: Build env file run: | touch .env - echo SHOPWARE_ENDPOINT=${{ vars.SHOPWARE_ENDPOINT }} >> .env - echo SHOPWARE_ACCESS_TOKEN=${{ vars.SHOPWARE_ACCESS_TOKEN }} >> .env + # echo ALLOW_ANONYMOUS_MERCURE=${{ vars.ALLOW_ANONYMOUS_MERCURE }} >> .env + echo SHOPWARE_STORE_API=${{ vars.SHOPWARE_STORE_API }} >> .env + echo SHOPWARE_ADMIN_API=${{ vars.SHOPWARE_ADMIN_API }} >> .env + echo SHOPWARE_STORE_API_ACCESS_TOKEN=${{ vars.SHOPWARE_STORE_API_ACCESS_TOKEN }} >> .env + echo SHOPWARE_STOREFRONT_URL=${{ vars.SHOPWARE_STOREFRONT_URL }} >> .env + echo ORIGIN=${{ vars.ORIGIN }} >> .env cat .env - name: Build code diff --git a/products/digital-sales-rooms/setup-3rd-party/realtime-service-mercure.md b/products/digital-sales-rooms/setup-3rd-party/realtime-service-mercure.md index 56a6baeb8..5f2c98988 100644 --- a/products/digital-sales-rooms/setup-3rd-party/realtime-service-mercure.md +++ b/products/digital-sales-rooms/setup-3rd-party/realtime-service-mercure.md @@ -14,7 +14,7 @@ Symfony provides a straightforward component, built on top of the [Mercure](http ## Setup hub -There are different ways to set up Mercure as listed below: +There are different ways to set up Mercure; we choose the quickest and easiest for you below: ### Setup via Stackhero (Recommended) @@ -34,69 +34,11 @@ There are different ways to set up Mercure as listed below: ### Setup via Docker -The docker image can be found at [dunglas/mercure](https://hub.docker.com/r/dunglas/mercure). It allows you to use the following *env* variables to configure Mercure. - ::: warning -Use different publisher and subscriber keys for security reasons. +For security reasons, use different publisher and subscriber keys in production mode. ::: -```txt -- MERCURE_PUBLISHER_JWT_KEY: your-256-bit-publisher-key -- MERCURE_SUBSCRIBER_JWT_KEY: your-256-bit-subscriber-key -- MERCURE_EXTRA_DIRECTIVES: |- - cors_origins "https://my-pwa-shop.com https://en.my-pwa-shop.com" - anonymous 0 - ui 1 -``` - -You can also configure it like the self-installed version via the Caddyfile. - -```txt -// Sample Caddyfile -{ - # Debug mode (disable it in production!) - debug - # HTTP/3 support -} -:80 -log -route { - redir / /.well-known/mercure/ui/ - encode gzip - mercure { - # Enable the demo endpoint (disable it in production!) - demo - # Publisher JWT key - publisher_jwt MySecret - # Subscriber JWT key - subscriber_jwt MySecret - # CORS - cors_origins http://localhost:3000 http://localhost:8080 http://shopware.test http://7779-91-90-160-158.ngrok.io - publish_origins localhost:3000 localhost:8080 shopware.test 7779-91-90-160-158.ngrok.io - # Allow anonymous subscribers (double-check that it's what you want) - anonymous - # Enable the subscription API (double-check that it's what you want) - subscriptions - } - respond "Not Found" 404 -} -``` - -### Self-host setup - -The [installation guide](https://mercure.rocks/docs/hub/install) explains all the steps that are required for installing the Mercure. - -```txt -mercure { -... -publisher_jwt my-publisher-key HS256 -subscriber_jwt my-subscriber-key HS256 -cors_origins "https://my-pwa-shop.com https://en.my-pwa-shop.com" -demo 0 -ui 0 -... -} -``` +You can clone our [local-mercure-sample](https://github.com/shopware/local-mercure-sample) and run it with docker-compose. ## Config Mercure hub diff --git a/products/extensions/b2b-components/order-approval/guides/03-payment-process.md b/products/extensions/b2b-components/order-approval/guides/03-payment-process.md index 843162c4d..2ba9e039b 100644 --- a/products/extensions/b2b-components/order-approval/guides/03-payment-process.md +++ b/products/extensions/b2b-components/order-approval/guides/03-payment-process.md @@ -19,7 +19,7 @@ The payment process of the order approval component can be customized by extendi Normally, after reviewer approves the order, the payment process will be executed automatically. However, if you just want to approve the order without executing the payment process, you can subscribe to the `PendingOrderApprovedEvent` event and set the `PendingOrderApprovedEvent::shouldProceedPlaceOrder` to `false`. This event is dispatched in the `Shopware\Commercial\B2B\OrderApproval\Storefront\Controller\ApprovalPendingOrderController::order` method. -```PHP +```php use Shopware\Commercial\B2B\OrderApproval\Event\PendingOrderApprovedEvent; diff --git a/products/extensions/b2b-components/order-approval/guides/04-add-new-approval-condition.md b/products/extensions/b2b-components/order-approval/guides/04-add-new-approval-condition.md index 282457441..4471a1411 100644 --- a/products/extensions/b2b-components/order-approval/guides/04-add-new-approval-condition.md +++ b/products/extensions/b2b-components/order-approval/guides/04-add-new-approval-condition.md @@ -15,7 +15,7 @@ To add a custom rule, following this document [Add custom rule](../../../../../g Example: -```PHP +```php cart_tax_status_rule_script @@ -194,7 +194,7 @@ We then use the variables `operator` and `totalPrice`, provided by the constrain ![App Approval Rule Condition Single Select](../../../../../assets/approval-rule-condition-single-select-example.png) ```xml -// manifest.xml + cart_tax_status_rule_script @@ -241,7 +241,7 @@ We then use the variables `operator` and `totalPrice`, provided by the constrain ![App Approval Rule Condition Multi Select](../../../../../assets/approval-rule-condition-multi-select-example.png) ```xml -// manifest.xml + cart_currency_rule_script diff --git a/products/extensions/b2b-components/quotes-management/guides/quotes-conversion.md b/products/extensions/b2b-components/quotes-management/guides/quotes-conversion.md index f3fe57e36..a5649b304 100644 --- a/products/extensions/b2b-components/quotes-management/guides/quotes-conversion.md +++ b/products/extensions/b2b-components/quotes-management/guides/quotes-conversion.md @@ -13,7 +13,7 @@ Customers can convert their shopping carts into quotes to facilitate seamless pr When a customer wants to request a quote for their shopping cart, the process involves converting a cart to an order and then proceeding to enrich the data for the quote. The method `convertToQuote` of class `Shopware\Commercial\B2B\QuoteManagement\Domain\CartToQuote\CartToQuoteConverter` is responsible for this process. -```PHP +```php use Shopware\Core\Checkout\Cart\Order\OrderConversionContext; use Shopware\Core\Checkout\Cart\Cart; use Shopware\Core\Checkout\Cart\Order\OrderConverter; @@ -36,7 +36,7 @@ public function convertToQuote(Cart $cart, SalesChannelContext $context, OrderCo When a customer wants to place an order based on a quote, a new cart is created based on the quote data. The method `convertToCart` of class `Shopware\Commercial\B2B\QuoteManagement\Domain\QuoteToCart\QuoteToCartConverter` is responsible for this process. -```PHP +```php use Shopware\Core\Checkout\Cart\Cart; use Shopware\Core\Framework\Uuid\Uuid; use Shopware\Core\System\SalesChannel\SalesChannelContext; diff --git a/products/paas/index.md b/products/paas/index.md index 09c9857c8..1e6218a43 100644 --- a/products/paas/index.md +++ b/products/paas/index.md @@ -24,6 +24,7 @@ Prerequisites: * Having a Shopware PaaS account (Select Register now on the authentication form when accessing ) * Having the project_id of an empty project created on Shopware PaaS * Having the Shopware PaaS CLI installed, see +* Having PHP ext-amqp installed (PaaS uses RabbitMQ instead of the regular DB to manage messages) ::: Steps: diff --git a/resources/guidelines/code/contribution.md b/resources/guidelines/code/contribution.md index 656edcd7d..5a266671f 100644 --- a/resources/guidelines/code/contribution.md +++ b/resources/guidelines/code/contribution.md @@ -25,7 +25,11 @@ To avoid your pull request getting rejected, you should always check that you pr * Check if your implementation is missing some important parts - For example, translations, backwards compatibility etc. * Provide the necessary tests for your implementation. * Check if there is already an existing pull request tackling the same issue. -* Write your commit messages in English, have them short and descriptive, and squash your commits meaningfully. +* Write your commit messages in English. The individual commit messages in the PR are not critical since the PR will be squashed on merge. However, ensure your **Pull Request title** follows the [Conventional Commits](https://www.conventionalcommits.org/) format, as this will become the final commit message. + * Example PR titles: + * `feat: Add new product import API` + * `fix: Resolve cart calculation issue` + * `docs: Update installation instructions` ::: danger Pull requests which do not fulfill these requirements will never be accepted by our team. To avoid your changes going through unnecessary workflow cycles, make sure to check this list with every pull request. @@ -33,7 +37,28 @@ Pull requests which do not fulfill these requirements will never be accepted by ## The developing workflow on GitHub -When you create a new pull request on GitHub, it will normally get the first sight within a week. We do regular meetings to screen all new pull requests on GitHub. In this meeting, there is a team of Shopware developers of different specializations who will discuss your changes. Together we decide what will happen next to your pull request. We will set one of the following labels, which indicates the status of the pull request. Here is a list of all possible states: +When you create a new pull request on GitHub, please ensure: + +1. Your PR title follows the **Conventional Commits** format as it will become the squashed commit message +2. You've provided all necessary information in the PR description +3. Your changes are complete and tested + +You are responsible for maintaining and updating your pull request. This includes: + +* Responding to review comments in a timely manner +* Updating the code according to review feedback +* Keeping the PR up to date with the target branch if conflicts arise +* Making sure that all pipeline checks succeed on your PR + +::: tip +Once your PR is public, avoid rebasing or force-pushing to the branch. Adding new commits makes it easier for reviewers to track changes and see what was updated in response to feedback. The PR will be automatically squashed when merged. +::: + +::: warning +Pull requests that become stale (no activity from the author for 2 weeks after a review or request for changes) will be closed. You can always reopen the pull request when you're ready to continue working on it. +::: + +Your PR will normally get the first review within a week. We do regular meetings to screen all new pull requests on GitHub. In this meeting, a team of Shopware developers with different specializations will discuss your changes. Together, we decide what will happen next to your pull request. We will set one of the following labels, which indicates the pull request's status. Here is a list of all possible states: | GitHub Label / Tag | What does it mean? | |:------------------------------------------------------------------------------------:| :--- | @@ -46,12 +71,8 @@ When you create a new pull request on GitHub, it will normally get the first sig ## What happens after a pull request has been created -Everyday weekdays, we assign the pull request to an Area (team) which is responsible for the specific part of the Shopware software. The Area will then review your pull request and decide what to do next. -The Area can either accept your pull request, decline it, or ask you to update it with more information or changes. - -The next step is that the pull request gets a "Scheduled" label. -This means that your pull request is now imported into our internal ticket system and will go through our internal workflow. -You will find a comment containing the GitHub Issue to follow the process. +Everyday weekdays, we assign the pull request to a Domain (team) which is responsible for the specific part of the Shopware software. The Area will then review your pull request and decide what to do next. +The team can either accept your pull request, decline it, or ask you to update it with more information or changes. ## Why a pull request gets declined diff --git a/resources/guidelines/documentation-guidelines/07-embedding-external-repositories.md b/resources/guidelines/documentation-guidelines/07-embedding-external-repositories.md index 1ffc1781c..73a63dba3 100644 --- a/resources/guidelines/documentation-guidelines/07-embedding-external-repositories.md +++ b/resources/guidelines/documentation-guidelines/07-embedding-external-repositories.md @@ -53,7 +53,7 @@ By default, contents are grouped under `General` section in the Algolia search u Update `sections: SwagSectionsConfig[]` with all the regex matches for your sections and define the title of new section displayed in the Algolia search modal. -```js +```javascript const sections: SwagSectionsConfig[] = [ // ... { @@ -71,7 +71,7 @@ Every article has a `Edit this page on GitHub` link in the bottom left corner. B You can do that by updating `const embeds: SwagEmbedsConfig[]`. -```js +```javascript const embeds: SwagEmbedsConfig[] = [ // ... { @@ -102,7 +102,7 @@ Update `themeConfig.swag.colorCoding` with your settings for color coding in the When you also want to share static assets from your repository such as `.pdf` or `.zip` files (excluding statically linked images in articles), make sure to copy them in the `buildEnd` hook. -```js +```javascript export default { // ... async buildEnd() { diff --git a/resources/guidelines/testing/store/quality-guidelines-apps/index.md b/resources/guidelines/testing/store/quality-guidelines-apps/index.md index 772c039de..6d06f87d5 100644 --- a/resources/guidelines/testing/store/quality-guidelines-apps/index.md +++ b/resources/guidelines/testing/store/quality-guidelines-apps/index.md @@ -277,7 +277,11 @@ However, you may employ ``, for instance. ### Do not use inline-css in the storefront templates -Use your own classes and let your CSS be compiled by the plugin. +Use your own classes and let your CSS be compiled by the app. + +### Prevent `!important` usage + +Please avoid using the `!important` rule whenever possible. [Add SCSS variables](https://developer.shopware.com/docs/guides/plugins/plugins/storefront/add-scss-variables.html#add-scss-variables) diff --git a/resources/guidelines/testing/store/quality-guidelines-plugins/index.md b/resources/guidelines/testing/store/quality-guidelines-plugins/index.md index 06e218711..82df24cd0 100644 --- a/resources/guidelines/testing/store/quality-guidelines-plugins/index.md +++ b/resources/guidelines/testing/store/quality-guidelines-plugins/index.md @@ -298,7 +298,11 @@ However, you may employ ``, for instance. ### Do not use inline-css in the storefront templates -Use your own classes and let your CSS be compiled by the app. +Use your own classes and let your CSS be compiled by the plugin. + +### Prevent `!important` usage + +Please avoid using the `!important` rule whenever possible. [Add SCSS variables](https://developer.shopware.com/docs/guides/plugins/plugins/storefront/add-scss-variables.html#add-scss-variables) diff --git a/resources/references/storefront-reference/plugin-reference.md b/resources/references/storefront-reference/plugin-reference.md index c267106dc..224681ef5 100644 --- a/resources/references/storefront-reference/plugin-reference.md +++ b/resources/references/storefront-reference/plugin-reference.md @@ -63,6 +63,7 @@ This is a list of available javascript plugins and helpers that can be used and | `ScrollUpPlugin` | Displays a small button with an "arrow up" icon to scroll back to the top of the page. Used on all pages and only displayed when the user has scrolled down the page. | --- | | `SearchWidgetPlugin` | Renders a dropdown with search result suggestions underneath the main headers search input field, as soon as the user starts to type a search term. | --- | | `SetBrowserClassPlugin` | Adds CSS classes to the `` element depending on the current device, e.g. `is-ipad`. These classes can be used to add styling for a specific device category. | --- | +| `SpeculationRulesPlugin` | If this javascript plugin is activated via `Admin > Settings > System > Storefront`, it adds speculation rules for the main navigation, the product listing and the header logo. | --- | | `VariantSwitchPlugin` | This plugin submits the variant form with the correct data option. Used on the product detail page to switch between product variants. | --- | | `WishlistWidgetPlugin` | Shows how many items are currently on the wishlist. Used by the wishlist "heart" icon inside the main header. | --- | | `ZoomModalPlugin` | Opens a full-screen modal window with an image gallery. Can contain multiple images that the user can zoom into. Used on the product detail page. | --- | diff --git a/snippets/guide/debugging_scheduled_tasks.md b/snippets/guide/debugging_scheduled_tasks.md new file mode 100644 index 000000000..b2e35f2b3 --- /dev/null +++ b/snippets/guide/debugging_scheduled_tasks.md @@ -0,0 +1,7 @@ +## Debugging scheduled tasks + +You can directly run a single scheduled task without the queue. This is useful for debugging purposes or to have better control of when and which tasks are executed. You can use `bin/console scheduled-task:run-single ` to run a single task. Example: + +```shell +bin/console scheduled-task:run-single log_entry.cleanup +``` \ No newline at end of file