ProductSetManager
extends Manager
in package
uses
ElasticReindexTrait
Abstract admin manager generic over the entity type and its service.
Tags
Table of Contents
Properties
- $service : ProductSetService
- $appContext : AppContext
- $cacheTagInvalidator : CacheTagInvalidator|null
- Post-commit invalidator of the wire-payload query cache (tag bump per entity class).
- $languageContext : LanguageContext|null
- $paramsConfig : Config|null
- Neon parameters (`%params%`: server paths and directories), set by the decorator (`decorators.neon`) like `setAppContext()`.
- $presenterContext : PresenterContext
- $settingContext : SettingContext
- $esDocumentSource : ProductSetDocumentSource
- $esIndexer : EsEntityIndexer
Methods
- __construct() : mixed
- delete() : Result
- deleteAll() : Result
- deleteOrHide() : Result
- Deletes from the grid: a set without history is hard deleted; a set referenced by an order, complaint or gift is only hidden (`deleted=1`). The history gate lives in the Api ({@see \App\UI\Api\Eshop\Models\Managers\ProductSetManager::findHistoryBlockers()}); here a `PRODUCT_SET_DELETE_BLOCKED` rejection is converted to a soft delete. Ids are processed one by one and the result follows {@see ProductManager::deleteOrHide()}.
- deletePriceSnapshot() : array{success: bool, code: string}
- Deletes a whole price snapshot through the bridge action `.../delete-price-snapshot`.
- duplicateCurrentPriceSnapshot() : bool
- Duplicates a variant: copies the currently valid price snapshot of the source set as the first and only row of the target set.
-
fetchAvailability()
: array<int, array{availableSets: ?int, inStock: bool, deliveryDays: ?int, labelWarehouseId: ?int, infoText: ?string, attributeClass: ?string, unmappedVariantIds: list
, unresolvedSetIds: list }> - Returns the availability of product sets in a batch, for the grid decoration and the stock panel in the edit form. `available` and `availableSets` are never cached.
- fetchCurrentPrices() : array<int, array{price: string, originalPrice: string, points: int, fromAmount: int, currencyId: int, vat: string, withVat: bool}>
- Returns the currently valid prices of product sets in a batch, for the grid decoration (`DataGrid::setRowDecorator`) and the "currently valid price" panel in the edit form.
- fetchDefaults() : array{userGroupId: int, currencyId: int, paymentRegionId: int}
- Returns the default catalog axes (base user group, default currency, default payment region) needed when the admin writes a price (inline variant price in the product pivot form).
- find() : SingleQuery<string|int, T>
- Finds one entity by id (returns a `SingleQuery` object).
- findAll() : Query<string|int, T>
- Finds all entities (returns a `Query` object).
- findBy() : SingleQuery<string|int, T>
- Finds one entity by filters (returns a `SingleQuery` object).
- getAppContext() : AppContext
- getLanguageContext() : LanguageContext|null
- getPresenterContext() : PresenterContext
- getSettingContext() : SettingContext
- getSettings() : array<int, array<string, mixed>>
- getTotalCount() : int|null
- Returns the total count of the last `findAll()` of this manager's service, computed only when the query asked for it (`findAll(..., computeTotalCount: true)`); otherwise the last stored value.
- initializeAllContexts() : void
- save() : Result
- savePriceSnapshot() : array{success: bool, code: string}
- Saves or replaces a price snapshot (price list tab) through the bridge action `.../save-price-snapshot`.
- setAppContext() : $this
- setCacheTagInvalidator() : static
- setLanguageContext() : $this
- setParamsConfig() : static
- setPresenterContext() : $this
- setSettingContext() : $this
- softDelete() : Result
- Soft deletes sets without a cascade (`deleted=1` instead of deleting rows) through the bridge action `.../soft-delete`. Has the same `int|array` signature as the generic {@see delete()} (group deletion in the grid sends an array of ids).
- updateColumn() : Result
- updateColumns() : Result
- bumpCacheTags() : void
- Bumps cache tags for the entity after commit: its class, the owned-cascade classes from metadata and the optional `additionalCacheTags()` of the manager.
- bumpCacheTagsExplicit() : void
- Bumps the given classes explicitly (raw-DBAL paths with a cross-entity effect).
- bumpCacheTagsForClass() : void
- Bumps cache tags by class name when there is no instance (bulk delete, `updateColumns()`, raw DBAL, tree operations).
- classCacheTags() : array<string|int, string>
- Returns extra tags for a bump that has no entity, typically tree operations ({@see \App\Core\Traits\Api\Models\Managers\TreeTrait::treeTransaction()}) that rewrite `lft`/`rgt` on many rows.
- esReindexBestEffort() : void
- Catches ES up after an admin mutation; it never breaks a write that is already in the database.
- getService() : TService
- Returns the service for the traits.
- touchForEsWatermark() : void
- Bumps `updateTime` for the watermark sync ({@see ElasticReindexTrait::save()}). Nothing else sets this column for product sets, so the sync would miss admin edits.
Properties
$service
public
ProductSetService
$service
$appContext
protected
AppContext
$appContext
$cacheTagInvalidator
Post-commit invalidator of the wire-payload query cache (tag bump per entity class).
protected
CacheTagInvalidator|null
$cacheTagInvalidator
= null
Set by the decorator (decorators.neon) like setParamsConfig(). Nullable and
fail-open: without wiring (or without Redis) a bump is a no-op.
$languageContext
protected
LanguageContext|null
$languageContext
= NULL
$paramsConfig
Neon parameters (`%params%`: server paths and directories), set by the decorator (`decorators.neon`) like `setAppContext()`.
protected
Config|null
$paramsConfig
= null
Write logic (asset directories) reads paths from here, not from getSettings() or the
setting context, which may be filled by the client without server paths. The property
cannot be named $config: it collides with the promoted $config in some managers.
$presenterContext
protected
PresenterContext
$presenterContext
$settingContext
protected
SettingContext
$settingContext
$esDocumentSource read-only
private
ProductSetDocumentSource
$esDocumentSource
$esIndexer read-only
private
EsEntityIndexer
$esIndexer
Methods
__construct()
public
__construct(ProductSetService $service, EsEntityIndexer $esIndexer, ProductSetDocumentSource $esDocumentSource) : mixed
Parameters
- $service : ProductSetService
- $esIndexer : EsEntityIndexer
- $esDocumentSource : ProductSetDocumentSource
delete()
public
delete(int|array<string|int, int> $id) : Result
Parameters
- $id : int|array<string|int, int>
Return values
ResultdeleteAll()
public
deleteAll([array<string|int, mixed> $filters = [] ]) : Result
Parameters
- $filters : array<string|int, mixed> = []
Return values
ResultdeleteOrHide()
Deletes from the grid: a set without history is hard deleted; a set referenced by an order, complaint or gift is only hidden (`deleted=1`). The history gate lives in the Api ({@see \App\UI\Api\Eshop\Models\Managers\ProductSetManager::findHistoryBlockers()}); here a `PRODUCT_SET_DELETE_BLOCKED` rejection is converted to a soft delete. Ids are processed one by one and the result follows {@see ProductManager::deleteOrHide()}.
public
deleteOrHide(int|array<int, int> $id) : Result
Parameters
- $id : int|array<int, int>
Return values
ResultdeletePriceSnapshot()
Deletes a whole price snapshot through the bridge action `.../delete-price-snapshot`.
public
deletePriceSnapshot(int $id, string $publishedTime) : array{success: bool, code: string}
Parameters
- $id : int
- $publishedTime : string
Return values
array{success: bool, code: string}duplicateCurrentPriceSnapshot()
Duplicates a variant: copies the currently valid price snapshot of the source set as the first and only row of the target set.
public
duplicateCurrentPriceSnapshot(int $sourceSetId, int $targetSetId) : bool
Runs admin-side over the existing bridge, with no extra Api action: findAll with includes
['prices'] (same channel as PriceSnapshotTrait::loadSnapshotSet()),
takes the rows with publishedTime = MAX(<= now) across all axes, then calls
savePriceSnapshot() with publishedTime=null (the bridge resolves it to "now", so the
copy is a new row, not a copy of the original date). History and VAT rows are not copied;
the static vatId fallback is copied by the set object graph. Returns false (no-op) when
the source does not exist or has no currently valid snapshot.
Parameters
- $sourceSetId : int
- $targetSetId : int
Return values
boolfetchAvailability()
Returns the availability of product sets in a batch, for the grid decoration and the stock panel in the edit form. `available` and `availableSets` are never cached.
public
fetchAvailability(array<string|int, int> $ids[, int|null $languageId = null ]) : array<int, array{availableSets: ?int, inStock: bool, deliveryDays: ?int, labelWarehouseId: ?int, infoText: ?string, attributeClass: ?string, unmappedVariantIds: list, unresolvedSetIds: list}>
Parameters
- $ids : array<string|int, int>
- $languageId : int|null = null
Return values
array<int, array{availableSets: ?int, inStock: bool, deliveryDays: ?int, labelWarehouseId: ?int, infoText: ?string, attributeClass: ?string, unmappedVariantIds: listfetchCurrentPrices()
Returns the currently valid prices of product sets in a batch, for the grid decoration (`DataGrid::setRowDecorator`) and the "currently valid price" panel in the edit form.
public
fetchCurrentPrices(array<string|int, int> $ids[, int|null $userGroupId = null ][, int|null $currencyId = null ][, int $amount = 1 ]) : array<int, array{price: string, originalPrice: string, points: int, fromAmount: int, currencyId: int, vat: string, withVat: bool}>
IMPORTANT: do not use the denormalized column product_sets.price; it is only a sort key
and does not hold the displayed price.
Parameters
- $ids : array<string|int, int>
- $userGroupId : int|null = null
- $currencyId : int|null = null
- $amount : int = 1
Return values
array<int, array{price: string, originalPrice: string, points: int, fromAmount: int, currencyId: int, vat: string, withVat: bool}>fetchDefaults()
Returns the default catalog axes (base user group, default currency, default payment region) needed when the admin writes a price (inline variant price in the product pivot form).
public
fetchDefaults() : array{userGroupId: int, currencyId: int, paymentRegionId: int}
Return values
array{userGroupId: int, currencyId: int, paymentRegionId: int}find()
Finds one entity by id (returns a `SingleQuery` object).
public
find(int $id[, string|array<string|int, mixed> $includes = [] ]) : SingleQuery<string|int, T>
Parameters
- $id : int
-
entity id
- $includes : string|array<string|int, mixed> = []
-
relations to load (
['translations', 'routes']or'*'for all)
Return values
SingleQuery<string|int, T>findAll()
Finds all entities (returns a `Query` object).
public
findAll([array<string|int, mixed>|null $filters = [] ][, array<string|int, mixed>|null $orderBy = null ][, int|null $offset = null ][, int|null $limit = null ][, array<string|int, mixed>|null $columns = null ][, string|array<string|int, mixed> $includes = [] ][, bool $computeTotalCount = false ]) : Query<string|int, T>
Parameters
- $filters : array<string|int, mixed>|null = []
-
filters for the where conditions
- $orderBy : array<string|int, mixed>|null = null
-
ordering
['column' => 'ASC/DESC'] - $offset : int|null = null
-
offset for pagination
- $limit : int|null = null
-
result limit
- $columns : array<string|int, mixed>|null = null
-
specific columns to load
- $includes : string|array<string|int, mixed> = []
-
relations to load (
['translations', 'routes.translations']or'*'for all) - $computeTotalCount : bool = false
-
whether to compute the total count for pagination
Return values
Query<string|int, T>findBy()
Finds one entity by filters (returns a `SingleQuery` object).
public
findBy([array<string|int, mixed> $filters = [] ][, string|array<string|int, mixed> $includes = [] ]) : SingleQuery<string|int, T>
Parameters
- $filters : array<string|int, mixed> = []
-
filters for the where conditions
- $includes : string|array<string|int, mixed> = []
-
relations to load (
['translations', 'routes']or'*'for all)
Return values
SingleQuery<string|int, T>getAppContext()
public
getAppContext() : AppContext
Return values
AppContextgetLanguageContext()
public
getLanguageContext() : LanguageContext|null
Return values
LanguageContext|nullgetPresenterContext()
public
getPresenterContext() : PresenterContext
Return values
PresenterContextgetSettingContext()
public
getSettingContext() : SettingContext
Return values
SettingContextgetSettings()
public
getSettings() : array<int, array<string, mixed>>
Return values
array<int, array<string, mixed>>getTotalCount()
Returns the total count of the last `findAll()` of this manager's service, computed only when the query asked for it (`findAll(..., computeTotalCount: true)`); otherwise the last stored value.
public
getTotalCount() : int|null
Same value as Query::getTotalCount() of that query.
Return values
int|nullinitializeAllContexts()
public
initializeAllContexts() : void
save()
public
save(BaseEntity $entity[, array<string, mixed> $meta = [] ]) : Result
Parameters
- $entity : BaseEntity
- $meta : array<string, mixed> = []
Return values
ResultsavePriceSnapshot()
Saves or replaces a price snapshot (price list tab) through the bridge action `.../save-price-snapshot`.
public
savePriceSnapshot(int $id, string|null $publishedTime, array<int, array{fromAmount: int, userGroupId: int, currencyId: int, price: string|float, originalPrice: string|float|null, points: int}> $rows[, string|null $replaceTime = null ]) : array{success: bool, code: string}
replaceTime is the publishedTime of the edited snapshot (null adds a new one).
Parameters
- $id : int
- $publishedTime : string|null
- $rows : array<int, array{fromAmount: int, userGroupId: int, currencyId: int, price: string|float, originalPrice: string|float|null, points: int}>
- $replaceTime : string|null = null
Return values
array{success: bool, code: string}setAppContext()
public
setAppContext(AppContext $appContext) : $this
Parameters
- $appContext : AppContext
Return values
$thissetCacheTagInvalidator()
public
setCacheTagInvalidator(CacheTagInvalidator $cacheTagInvalidator) : static
Parameters
- $cacheTagInvalidator : CacheTagInvalidator
Return values
staticsetLanguageContext()
public
setLanguageContext(LanguageContext|null $languageContext) : $this
Parameters
- $languageContext : LanguageContext|null
Return values
$thissetParamsConfig()
public
setParamsConfig(Config $paramsConfig) : static
Parameters
- $paramsConfig : Config
Return values
staticsetPresenterContext()
public
setPresenterContext(PresenterContext $presenterContext) : $this
Parameters
- $presenterContext : PresenterContext
Return values
$thissetSettingContext()
public
setSettingContext(SettingContext $settingContext) : $this
Parameters
- $settingContext : SettingContext
Return values
$thissoftDelete()
Soft deletes sets without a cascade (`deleted=1` instead of deleting rows) through the bridge action `.../soft-delete`. Has the same `int|array` signature as the generic {@see delete()} (group deletion in the grid sends an array of ids).
public
softDelete(int|array<int, int> $id) : Result
Parameters
- $id : int|array<int, int>
Return values
ResultupdateColumn()
public
updateColumn(int|array<string|int, int> $entityId, string $property, mixed $value) : Result
Parameters
- $entityId : int|array<string|int, int>
- $property : string
- $value : mixed
Return values
ResultupdateColumns()
public
updateColumns(int|array<string|int, int> $entityId, array<string, mixed> $values) : Result
Parameters
- $entityId : int|array<string|int, int>
- $values : array<string, mixed>
Return values
ResultbumpCacheTags()
Bumps cache tags for the entity after commit: its class, the owned-cascade classes from metadata and the optional `additionalCacheTags()` of the manager.
protected
bumpCacheTags(object $entity) : void
Fail-open (the invalidator swallows exceptions). Called from the manager Save/Delete/Tree traits after the commit.
Parameters
- $entity : object
bumpCacheTagsExplicit()
Bumps the given classes explicitly (raw-DBAL paths with a cross-entity effect).
protected
bumpCacheTagsExplicit(array<string|int, string> $classes) : void
Parameters
- $classes : array<string|int, string>
bumpCacheTagsForClass()
Bumps cache tags by class name when there is no instance (bulk delete, `updateColumns()`, raw DBAL, tree operations).
protected
bumpCacheTagsForClass(class-string $rootClass[, array<string|int, string> $extraTags = [] ]) : void
Bumps the root class and its owned-cascade classes.
Parameters
- $rootClass : class-string
- $extraTags : array<string|int, string> = []
classCacheTags()
Returns extra tags for a bump that has no entity, typically tree operations ({@see \App\Core\Traits\Api\Models\Managers\TreeTrait::treeTransaction()}) that rewrite `lft`/`rgt` on many rows.
protected
classCacheTags() : array<string|int, string>
IMPORTANT: additionalCacheTags(object) receives an entity, so a class-level bump cannot
use it; without this hook a delete would lose the cross-entity tag (Comment to
CommentThread). A manager whose cross-entity tag does not depend on a particular
entity returns it here.
NOTE: unlike additionalCacheTags(), this hook is declared (with an empty default)
instead of being an opt-in through method_exists(); method_exists() is always true in
a manager that has the method, which phpstan reports as alreadyNarrowedType.
Return values
array<string|int, string>esReindexBestEffort()
Catches ES up after an admin mutation; it never breaks a write that is already in the database.
protected
esReindexBestEffort(array<string|int, int> $ids) : void
Parameters
- $ids : array<string|int, int>
getService()
Returns the service for the traits.
protected
getService() : TService
Return values
TServicetouchForEsWatermark()
Bumps `updateTime` for the watermark sync ({@see ElasticReindexTrait::save()}). Nothing else sets this column for product sets, so the sync would miss admin edits.
protected
touchForEsWatermark(BaseEntity $entity) : void
Parameters
- $entity : BaseEntity