ProductSetManager
extends Manager
in package
Abstract front 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
- $priceDisplay : array<int, array{paymentRegionId: int, chargeVat: bool, noteKey: ?string}>
- Request cache of the VAT engine display treatment, per display payment region.
- $productSets : ProductSetService
- NOTE: the service is also held in a typed property. The parent `$service` is annotated as `ServiceInterface<TService>`, so PHPStan does not see the own methods of the concrete service (batch read passthroughs). Rewriting the annotation to `TService` in Core is possible, but managers without `@extends` would then get `TService = object` and about 60 `method.notFound` errors; this is cheaper and local.
Methods
- __construct() : mixed
-
fetchAvailability()
: array<int, array{availableSets: ?int, inStock: bool, deliveryDays: ?int, labelWarehouseId: ?int, infoText: ?string, attributeClass: ?string, unmappedVariantIds: list
, unresolvedSetIds: list }> - Passthrough to the bridge action `.../availability` ({@see \App\UI\Api\Eshop\Models\Managers\ProductSetManager::getAvailabilities()} batch); see {@see \App\UI\Front\Eshop\Models\Repositories\Api\ProductSetRepository::fetchAvailability()}.
- fetchCurrentPrices() : array<int, array{price: string, originalPrice: string, points: int, fromAmount: int, currencyId: int, vat: string, withVat: bool}>
- Passthrough to the bridge action `.../current-prices` (`PriceResolver` batch); see {@see \App\UI\Front\Eshop\Models\Repositories\Api\ProductSetRepository::fetchCurrentPrices()}.
- fetchGifts() : array<int, array{name: string, amount: int}>
- See {@see \App\UI\Front\Eshop\Models\Repositories\Api\ProductSetRepository::fetchGifts()}.
- fetchNextPriceTimes() : array<int, DateTimeImmutable>
- Returns the end of the deal for the countdown in the "Deal of the week" section (`LastProductList::renderDeal()`): the nearest future `published_time` among the prices of each given set, in the same currency as the displayed price.
- fetchParameterValueCounts() : array<int, array<string|int, int>>
- Returns set counts by parameter value; see {@see \App\UI\Api\Eshop\Models\Managers\ProductSetManager::fetchParameterValueCounts()}.
- fetchPriceDisplay() : array{paymentRegionId: int, chargeVat: bool, noteKey: ?string}
- Returns the catalog display treatment: passthrough to the bridge action `.../price-display` with a per-region request cache (see {@see self::$priceDisplay}).
- find() : SingleQuery<string|int, T>
- Finds one entity by ID and returns a `SingleQuery` object.
- findAll() : Query<string|int, T>
- Finds all entities and returns a `Query` object.
- findBy() : SingleQuery<string|int, T>
- Finds one entity by filters and 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
- isVatCharged() : bool
- Returns whether catalog prices (always the base without VAT) are shown with VAT added in the given display payment region.
- registerView() : void
- Records a set detail view into the daily statistics (tracking for the `Statistics` dashboard).
-
search()
: ProductSet>, 1: int, 2: bool, 3: array
>} |null - Searches through the Api endpoint `api/eshop/product-set/search`.
- setAppContext() : $this
- setCacheTagInvalidator() : static
- setLanguageContext() : $this
- setParamsConfig() : static
- setPresenterContext() : $this
- setSettingContext() : $this
- 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.
- getService() : TService
- Returns the service for the traits.
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
$priceDisplay
Request cache of the VAT engine display treatment, per display payment region.
private
array<int, array{paymentRegionId: int, chargeVat: bool, noteKey: ?string}>
$priceDisplay
= []
The manager is a DI singleton within a request, so the seller and rate (bridge to
TaxManager::resolveDisplay()) are read once per region per request, even when the list,
the detail and the promo component all ask.
keyed by $paymentRegionId (0 = default region, null argument)
$productSets read-only
NOTE: the service is also held in a typed property. The parent `$service` is annotated as `ServiceInterface<TService>`, so PHPStan does not see the own methods of the concrete service (batch read passthroughs). Rewriting the annotation to `TService` in Core is possible, but managers without `@extends` would then get `TService = object` and about 60 `method.notFound` errors; this is cheaper and local.
private
ProductSetService
$productSets
Methods
__construct()
public
__construct(ProductSetService $service) : mixed
Parameters
- $service : ProductSetService
fetchAvailability()
Passthrough to the bridge action `.../availability` ({@see \App\UI\Api\Eshop\Models\Managers\ProductSetManager::getAvailabilities()} batch); see {@see \App\UI\Front\Eshop\Models\Repositories\Api\ProductSetRepository::fetchAvailability()}.
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()
Passthrough to the bridge action `.../current-prices` (`PriceResolver` batch); see {@see \App\UI\Front\Eshop\Models\Repositories\Api\ProductSetRepository::fetchCurrentPrices()}.
public
fetchCurrentPrices(array<string|int, int> $ids[, int|null $userGroupId = null ][, int|null $currencyId = null ][, int $amount = 1 ][, int|null $paymentRegionId = null ]) : array<int, array{price: string, originalPrice: string, points: int, fromAmount: int, currencyId: int, vat: string, withVat: bool}>
Parameters
- $ids : array<string|int, int>
- $userGroupId : int|null = null
- $currencyId : int|null = null
- $amount : int = 1
- $paymentRegionId : int|null = null
Return values
array<int, array{price: string, originalPrice: string, points: int, fromAmount: int, currencyId: int, vat: string, withVat: bool}>fetchGifts()
See {@see \App\UI\Front\Eshop\Models\Repositories\Api\ProductSetRepository::fetchGifts()}.
public
fetchGifts(int $setId[, int|null $languageId = null ]) : array<int, array{name: string, amount: int}>
Parameters
- $setId : int
- $languageId : int|null = null
Return values
array<int, array{name: string, amount: int}>fetchNextPriceTimes()
Returns the end of the deal for the countdown in the "Deal of the week" section (`LastProductList::renderDeal()`): the nearest future `published_time` among the prices of each given set, in the same currency as the displayed price.
public
fetchNextPriceTimes(array<string|int, int> $setIds[, int|null $currencyId = null ]) : array<int, DateTimeImmutable>
The Front must not read the price list table (see fetchCurrentPrices()), so it uses
the same bridge path (ProductSetRepository::fetchNextPriceTimes()
then ProductSetPresenter::internalActionNextPriceTimes()).
It is a batch because the deal selection walks several discounted candidates and must not
call the bridge per candidate (prepareDealItem()).
published_time is stored as a UTC digit string, so it is parsed explicitly in UTC;
otherwise DateTimeImmutable would take the ambient request timezone (Europe/Prague) and
the countdown would be off by 1-2 hours. An unparsable value is skipped so that one set
cannot fail the whole batch query.
Parameters
- $setIds : array<string|int, int>
- $currencyId : int|null = null
Return values
array<int, DateTimeImmutable> —setId => end of the deal; a set without a scheduled future price (in the given currency) is simply absent, so the component renders no countdown
fetchParameterValueCounts()
Returns set counts by parameter value; see {@see \App\UI\Api\Eshop\Models\Managers\ProductSetManager::fetchParameterValueCounts()}.
public
fetchParameterValueCounts(array<int, object> $filters) : array<int, array<string|int, int>>
Parameters
- $filters : array<int, object>
Return values
array<int, array<string|int, int>> —parameterId => [value => count]
fetchPriceDisplay()
Returns the catalog display treatment: passthrough to the bridge action `.../price-display` with a per-region request cache (see {@see self::$priceDisplay}).
public
fetchPriceDisplay([int|null $paymentRegionId = null ]) : array{paymentRegionId: int, chargeVat: bool, noteKey: ?string}
Parameters
- $paymentRegionId : int|null = null
Return values
array{paymentRegionId: int, chargeVat: bool, noteKey: ?string}find()
Finds one entity by ID and returns a `SingleQuery` object.
public
find(int $id[, string|array<string|int, mixed> $includes = [] ]) : SingleQuery<string|int, T>
Usage:
$query = $manager->find(1, ['translations']);
$entity = $query->include(['routes'])->execute(); // or ->get()
$title = $query->getTitle(); // magic call, forwarded to the entity
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 and 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>
Usage:
$query = $manager->findAll(['active' => true], ['created' => 'desc']);
$items = $query->include(['translations'])->limit(10)->execute();
foreach ($query as $item) { ... } // the query runs lazily on iteration
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 and returns a `SingleQuery` object.
public
findBy([array<string|int, mixed> $filters = [] ][, string|array<string|int, mixed> $includes = [] ]) : SingleQuery<string|int, T>
Usage:
$query = $manager->findBy(['slug' => 'my-page'], ['translations']);
$entity = $query->include(['routes'])->execute(); // or ->get()
$title = $query->getTitle(); // magic call, forwarded to the entity
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
isVatCharged()
Returns whether catalog prices (always the base without VAT) are shown with VAT added in the given display payment region.
public
isVatCharged([int|null $paymentRegionId = null ]) : bool
Decided only by chargeVat of the VAT engine; sellers.show_prices_with_vat is no longer
read, a VAT payer always shows the price with VAT.
Parameters
- $paymentRegionId : int|null = null
Return values
boolregisterView()
Records a set detail view into the daily statistics (tracking for the `Statistics` dashboard).
public
registerView(int $id) : void
Called from ProductSetDetailTrait::actionDetail() after the eligibility guard (a 404 is
not tracked). The auxiliary statistic must not fail or slow down the detail: an error of
the bridge call (Api unavailable, network) is swallowed here and the page renders anyway.
Parameters
- $id : int
search()
Searches through the Api endpoint `api/eshop/product-set/search`.
public
search(string $search, string|null $languageAlias[, array<int, object|array<string, mixed>> $filters = [] ][, array<string, mixed>|null $orderBys = null ][, int|null $offset = null ][, int|null $limit = null ][, string|array<int, string> $includes = [] ]) : ProductSet>, 1: int, 2: bool, 3: array>} |null
Without orderBys Elasticsearch sorts and paginates by relevance (fromEs: true); with
orderBys (manual user choice) the DB sorts, paginates and counts over the ES id set and
relevance is not used.
Parameters
- $search : string
- $languageAlias : string|null
- $filters : array<int, object|array<string, mixed>> = []
-
visibility filters (level, banned, deleted, deactivated); the endpoint applies them in both paths, ES ids are only candidates
- $orderBys : array<string, mixed>|null = null
- $offset : int|null = null
- $limit : int|null = null
- $includes : string|array<int, string> = []
Return values
ProductSet>, 1: int, 2: bool, 3: array[entities in response order, totalCount, fromEs, highlights]; null = the endpoint
gave no list (DENY/outage), so the caller uses the plain DB path
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
$thisbumpCacheTags()
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>getService()
Returns the service for the traits.
protected
getService() : TService