CoolCMS API

ProductSetManager extends Manager
in package

Abstract front manager generic over the entity type and its service.

Tags
extends

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

$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.

$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.

$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

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: list, unresolvedSetIds: list}>

fetchCurrentPrices()

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>

getSettings()

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|null

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
bool

registerView()

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

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>}|null —

[entities in response order, totalCount, fromEs, highlights]; null = the endpoint gave no list (DENY/outage), so the caller uses the plain DB path

setParamsConfig()

public setParamsConfig(Config $paramsConfig) : static
Parameters
$paramsConfig : Config
Return values
static

bumpCacheTags()

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
Return values
TService
On this page

Search results