Skip to content

Execution Flows

Step-by-step traces through product save, product load, category operations, price calculation, and indexer execution flows.

1. Product Save via Repository

The ProductRepositoryInterface::save() method is the primary entry point for persisting product data. This flow handles validation, EAV attribute storage, media gallery, and triggers indexer invalidation.

1

Entry Point: ProductRepository::save()

Receives ProductInterface object. Validates SKU uniqueness if creating new product.

Magento\Catalog\Model\ProductRepository::save($product, $saveOptions = false)
2

Validation & Preparation

  • - Validate required attributes (name, sku, price, status, visibility)
  • - Process extension attributes (stock, categories, tier prices)
  • - Handle media gallery entries
  • - Resolve attribute set if not provided
3

Before Save Plugins

Plugins intercept before persisting. Key plugins include:

  • - InventoryPlugin: Reserve stock
  • - CategoryLinkPlugin: Process category assignments
  • - UrlRewritePlugin: Generate URL rewrites
4

ResourceModel::save() - EAV Persistence

The core persistence layer saves entity and all EAV attribute values.

// Transaction starts
INSERT INTO catalog_product_entity (sku, type_id, attribute_set_id, ...)
INSERT INTO catalog_product_entity_varchar (entity_id, attribute_id, store_id, value)
INSERT INTO catalog_product_entity_int (entity_id, attribute_id, store_id, value)
INSERT INTO catalog_product_entity_decimal (entity_id, attribute_id, store_id, value)
// ... for each attribute type
// Transaction commits
5

Event: catalog_product_save_after

Observers process post-save logic:

  • - ImageResizeAfterProductSave: Queue image resize
  • - IndexerPlugin: Invalidate affected indexes
  • - FullPageCache: Flush product cache tags
6

Indexer Invalidation

If indexers are in "Update on Schedule" mode, changelogs are updated. Otherwise, partial reindex runs.

  • - catalog_product_price
  • - catalog_product_flat (if enabled)
  • - catalog_category_product
  • - catalogsearch_fulltext

Performance Note

Saving products with many attributes or media gallery images can be slow. Use $saveOptions = true to skip validation for bulk imports. Always batch save operations and consider disabling indexers during large imports.

2. Product Load via Repository

Loading a product via ProductRepositoryInterface::get() or getById() retrieves the entity and all its EAV attributes based on the current store scope.

1

Entry: ProductRepository::get($sku) or getById($id)

Check instance cache first. If not cached, proceed to load.

// Instance cache check
if (isset($this->instances[$sku][$storeId])) {
    return $this->instances[$sku][$storeId];
}
2

ResourceModel::load() - EAV Assembly

Multiple JOINs retrieve all attribute values for the entity:

SELECT e.*,
       t_varchar.value AS name,
       t_decimal.value AS price,
       t_int.value AS status
FROM catalog_product_entity e
LEFT JOIN catalog_product_entity_varchar t_varchar
    ON e.entity_id = t_varchar.entity_id
    AND t_varchar.attribute_id = 73 /* name */
    AND t_varchar.store_id IN (0, 1)
LEFT JOIN catalog_product_entity_decimal t_decimal
    ON e.entity_id = t_decimal.entity_id
    AND t_decimal.attribute_id = 77 /* price */
-- ... repeated for each attribute
3

Extension Attributes Loading

After entity load, extension attributes are hydrated via ReadExtensions:

  • - Stock data (qty, is_in_stock)
  • - Category links
  • - Tier prices
  • - Bundle/Configurable options (if applicable)
4

Event: catalog_product_load_after

Observers can modify the loaded product. Entity is then cached and returned.

N+1 Query Warning

Loading products in a loop causes N+1 query issues. Always use ProductCollectionFactory with addAttributeToSelect() for batch loading. The Flat Catalog avoids EAV JOINs for frontend queries.

3. Category Save Flow

Category save is similar to product save but includes tree path recalculation and children_count updates.

Key Operations

  1. Validate parent category exists
  2. Calculate path: parent_path + "/" + entity_id
  3. Set level = parent_level + 1
  4. Update parent's children_count
  5. Save EAV attributes
  6. Recalculate children paths if moved
  7. Trigger reindex of category tree

Events Dispatched

  • catalog_category_prepare_save
  • catalog_category_save_before
  • catalog_category_save_after
  • clean_cache_by_tags (FPC)

4. Price Calculation Flow

Price calculation is one of the most complex flows in Catalog. The final price depends on base price, special price, tier prices, catalog rules, customer group, and tax configuration.

1

Get Base Price

Read price attribute from EAV or indexed price table.

2

Apply Special Price

If special_price is set and within special_from_date / special_to_date, use it.

3

Apply Tier Prices

Check catalog_product_entity_tier_price for quantity-based discounts by customer group.

4

Apply Catalog Price Rules

Query catalogrule_product_price for applicable rule discounts.

5

Return Final Price

Lowest applicable price is returned. For display, tax may be added based on configuration.

Critical Warning: getPrice() vs getFinalPrice()

$product->getPrice() returns the BASE price attribute only. $product->getFinalPrice() runs the full price calculation. This is a common source of bugs. Always use getFinalPrice() for customer-facing prices.

5. Indexer Execution Flow

Indexers transform EAV data into flat, query-optimized tables. They can run in "Update on Save" (immediate) or "Update on Schedule" (cron-based) modes.

Update on Save Mode

  1. 1 Entity save triggers IndexerPlugin
  2. 2 Plugin calls Indexer::reindexRow($id)
  3. 3 Flat table updated immediately
  4. 4 Cache tags invalidated

Update on Schedule Mode

  1. 1 Entity save writes to changelog table
  2. 2 Cron job runs indexer:reindex
  3. 3 Mview reads changelog, reindexes affected IDs
  4. 4 Changelog entries marked processed
# Reindex all catalog indexers
bin/magento indexer:reindex catalog_product_flat catalog_category_flat \
    catalog_category_product catalog_product_price catalog_product_attribute

# Check indexer status
bin/magento indexer:status

6. Frontend Product View Flow

When a customer visits a product page, the request flows through controller, block, and template layers with full-page cache optimization.

1

Route: /catalog/product/view/id/{id}

Controller: Magento\Catalog\Controller\Product\View

2

Product Load with View Helper

ProductViewHelper::prepareAndRender() loads product with design settings.

3

Layout Processing

Layout handles applied in order:

  • - default
  • - catalog_product_view
  • - catalog_product_view_type_{type_id}
  • - catalog_product_view_id_{product_id}
4

Block Rendering

Key blocks: product.info, product.info.price, product.info.media, product.info.options

5

Full Page Cache

Response cached with tags: cat_p_{id}, cat_c_{category_ids}. Hole-punching for private data (cart, customer).