Skip to content

Backend Architecture

This page maps Bagisto's server side: how a request travels through the application, the building blocks every package uses, and what each of the 42 core packages holds. Each section links to the guide that explains its topic in full.

How a Request Is Handled

  1. public/index.php boots the application from bootstrap/app.php. Laravel loads every service provider in bootstrap/providers.php, and Concord loads the modules listed in config/concord.php.

  2. The global middleware added in bootstrap/app.php runs: Webkul\Core\Http\Middleware\SecureHeaders sets the security headers, and Webkul\Installer\Http\Middleware\CanInstall sends every request to /install until Bagisto is installed.

  3. The route decides which middleware stack applies:

    AreaRoutesMiddleware
    Adminpackages/Webkul/Admin/src/Routes/, prefixed with config('app.admin_url')web and Bagisto's maintenance check; every page except sign-in, password reset and two-factor verification also passes admin (the Bouncer: sign-in, account status, permissions, two-factor authentication) and NoCacheMiddleware
    Storefrontpackages/Webkul/Shop/src/Routes/web.php and api.phpweb, the shop group (Theme, Locale, Currency) and the maintenance check; the home, category, product, CMS, search, compare and contact pages add cache.response for the full page cache
    Payment gatewaysRoutes/ in the Stripe, PayU, Razorpay, PhonePe and PayGlocal packages, and Http/routes.php in PaypalSet by each gateway
    Web installerpackages/Webkul/Installer/src/Routes/web.phpweb, with the installer's own session and locale middleware
  4. The controller reads and writes data through repositories, which return Concord models. Writes are wrapped in before and after events. Controllers, repositories, DataGrids and listeners are resolved from the container, so a package can bind a subclass in place of a core one.

  5. The response is usually a Blade view. The Theme package resolves shop:: and admin:: views against the active theme before the package's own views (how views are resolved), and view_render_event() calls in the templates let other packages add markup.

  6. In the browser, the layout loads the Vite bundle and mounts the Vue app; see Frontend Architecture.

Models, Contracts and Proxies

Bagisto uses Concord so that one package can replace another package's model without editing it. Every entity has three parts:

PartExampleRole
ContractWebkul\Category\Contracts\CategoryAn empty interface that names the entity
ModelWebkul\Category\Models\CategoryThe Eloquent model, which implements the contract
ProxyWebkul\Category\Models\CategoryProxyResolves to whichever model is registered for the contract

A package lists its models in the $models array of its ModuleServiceProvider, which in most core packages extends Webkul\Core\Providers\CoreModuleServiceProvider. Code that crosses packages refers to the contract or the proxy, never the concrete model: a repository's model() returns the contract, and a relation uses the proxy, as in RMAStatusProxy::modelClass(). See Models, including Extending a Core Model.

Repositories

All database access goes through repositories. A repository extends Webkul\Core\Eloquent\Repository, which extends Prettus's BaseRepository, and its model() method returns the contract of the model it works with, such as 'Webkul\Attribute\Contracts\AttributeGroup'.

  • On top of Prettus's methods, the base class adds findOneByField(), findOneWhere(), findOrFail(), sum(), avg() and getModel().
  • It caches reads, controlled by config/repository.php and invalidated through a per-repository generation token; see Repository Cache.
  • Controllers, listeners and jobs receive repositories through constructor injection. The one place allowed to build a query directly is a DataGrid's prepareQueryBuilder().

See Repositories.

Events and View Render Events

Bagisto's events are dot-delimited strings, usually fired in before and after pairs around a write:

File: packages/Webkul/Admin/src/Http/Controllers/Catalog/ProductController.php

php
Event::dispatch('catalog.product.update.before', $id);

$product = $this->productRepository->update($request->all(), $id);

Event::dispatch('catalog.product.update.after', $product);

Each package maps listeners to event names in the $listen array of its own EventServiceProvider; see Event Listeners for the events core fires.

Core templates also call view_render_event() at named points, such as bagisto.shop.layout.body.after. A package adds markup there by listening for the event and adding a template to the Webkul\Theme\ViewRenderEventManager; see View Render Events.

The admin menu, the permissions, the system configuration fields and several registries are PHP arrays that packages merge into shared configuration keys with mergeConfigFrom(), in their service provider's register() method:

Config keyCore entriesUsed for
menu.adminAdmin/src/Config/menu.phpThe admin sidebar, read through menu() (Webkul\Core\Menu), which hides items the admin has no permission for
menu.customerShop/src/Config/menu.phpThe customer account menu
aclAdmin/src/Config/acl.phpRole permissions, read through acl() (Webkul\Core\Acl); the Bouncer maps each route name to a permission key
coreAdmin/src/Config/system.phpSystem configuration fields, read through system_config() (Webkul\Core\SystemConfig); saved values come from core()->getConfigData($field, $channel, $locale)
payment_methodsConfig/payment-methods.php in Payment and each gatewayPayment methods
carriersShipping/src/Config/carriers.phpShipping methods
product_typesProduct/src/Config/product_types.phpProduct types
importersDataTransfer/src/Config/importers.phpImport types

In core, the Admin package defines the menu items, permissions and configuration fields for every package. Your package merges its own files into the same keys; see Menu, Access Control List and System Configuration. mergeConfigFrom() keeps an entry that is already set, so a package changes the class behind a core payment method, carrier, product type or importer from its provider's boot() instead; see Overriding a Core Type.

DataGrids

Admin listings extend Webkul\DataGrid\DataGrid and implement prepareQueryBuilder() and prepareColumns(), and optionally prepareActions() and prepareMassActions(). The controller returns datagrid(ProductDataGrid::class)->process() for the listing's AJAX request, and process() applies the requested filters, sorting, pagination and export. See DataGrid.

Helpers

Packages define global helper functions in their src/Http/helpers.php:

HelperReturnsPackage
core()Webkul\Core\Core: channels, locales, currencies and configuration valuesCore
menu(), acl(), system_config()The menu, ACL and system configuration registriesCore
db_grammar()SQL fragments for the active database (MySQL, MariaDB or PostgreSQL)Core
clean_content()HTML passed through HTMLPurifier, with Blade syntax removedCore
bouncer()Permission checks for the signed-in adminUser
two_factor_authentication()Webkul\User\TwoFactorAuthenticationUser
cart()The current cart (Webkul\Checkout\Cart)Checkout
payment(), shipping()The payment and shipping method registriesPayment, Shipping
datagrid()An instance of the given DataGrid classDataGrid
themes()The theme registry (Webkul\Theme\Themes)Theme
bagisto_asset()The URL of a file a theme shipsTheme
bagisto_theme_storage()Webkul\Theme\ThemeStorage, for media a theme section storesTheme
view_render_event()The rendered output of a view render eventTheme
image_manager(), image_urls()Laravel's image manager, and the resized URLs of an imageImageCache
product_image(), product_video(), product_toolbar()Product media and listing toolbar helpersProduct
magic_ai()The Generative AI (Magic AI) serviceMagicAI

Understanding the Core Class documents core() method by method.

Packages

Each package is autoloaded from composer.json, registers its service provider in bootstrap/providers.php and, when it has models, its ModuleServiceProvider in config/concord.php; How a Package Is Wired In has the details, and Inside a Package its directories. DebugBar, FPC, ImageCache, Installer, MagicAI, PhonePe and SocialShare have no module provider, and Admin, PayGlocal, Payment, Paypal, PayU, Razorpay, Rule, Shipping, Shop and Stripe have one with an empty $models list. bootstrap/providers.php also lists Webkul\Core\Providers\EnvValidatorServiceProvider, which stops the application when DB_PREFIX contains anything other than letters, digits and underscores.

PackageWhat it holds
AdminThe admin: routes, controllers, views, DataGrids, reporting, the command palette, and the menu, ACL and configuration fields
AttributeAttributes, attribute options, groups and families
BookingProductThe booking product type: default, appointment, event, rental and table slots, and bookings
CartRuleCart price rules, coupons and coupon usage
CatalogRuleCatalog price rules and their per-product prices
CategoryThe nested-set category tree and its translations
CheckoutThe cart: items, addresses, payment and shipping rates
CMSCMS pages and their translations
CoreChannels, locales, currencies, exchange rates, countries and states, saved configuration and newsletter subscribers; the core() helpers, the menu, ACL and configuration registries, the database grammar, the dynamic SMTP mailer and the storage driver
CustomerCustomers, groups, addresses, notes, wishlists, compare items and the customer captcha
DataGridThe DataGrid base class, column types, saved filters and export
DataTransferImports: the importer registry, import batches and queued jobs
DebugBarDebugBar integration, with a collector that groups models, views and queries by package
EUWithdrawalEU right-of-withdrawal requests
FPCThe full page cache on spatie/laravel-responsecache: cache profile, hasher, replacers and invalidation listeners
GDPRCustomer data requests
ImageCacheResized images served at cache/{template}/{path}, and the template registry
Installerbagisto:install, the web installer and the seeders
InventoryInventory sources
MagicAIGenerative AI (Magic AI) through the Laravel AI SDK
MarketingCampaigns, email templates, events, search terms, search synonyms and URL rewrites
NotificationAdmin notifications for orders
OmnibusPrice snapshots and the 30-day lowest price for the EU Omnibus directive
PayGlocalThe PayGlocal payment gateway
PaymentThe base payment class, cash on delivery, money transfer and the payment_methods registry
PaypalPayPal Smart Button and PayPal Standard
PayUThe PayU payment gateway
PhonePeThe PhonePe payment gateway
ProductProducts, product types, attribute values, images, videos, reviews, customer group prices, customizable options, inventories, the flat table, and the price, inventory, flat and search indexers
RazorpayThe Razorpay payment gateway
RMAReturns: requests, items, reasons, rules, statuses, custom fields and messages
RuleThe condition engine that cart rules and catalog rules share
SalesOrders, invoices, shipments, refunds, transactions and purchased downloadable links
ShippingThe base carrier class, flat rate and free shipping, and the carriers registry
ShopThe storefront: routes, controllers, views, Blade components, the customer account, the storefront's JSON API and WebMCP
SitemapXML sitemaps
SocialLoginCustomer sign-in through social accounts
SocialShareShare links for products
StripeThe Stripe payment gateway
TaxTax categories, tax rates and the mapping between them
ThemeThe theme registry and view finder, @bagistoVite, Appearance sections, theme storage and view render events
UserAdmins, roles, the Bouncer middleware and two-factor authentication

Released under the MIT License.