AdvertDocumentSource
in package
implements
HighlightableDocumentSourceInterface, VisibilityConstrainedDocumentSourceInterface
Elasticsearch documents of a company profile (Comcat `Advert`).
A profile is single-language (language = insertLanguageId), so there is one document in the
index of that language (comcat_advert_{alias}) with _id = "{advertId}_{languageId}".
Comcat is a standalone stack: no classes are shared with Bazaar, it has its own AdvertService
and BlacklistedWordManager; only the Core/Base/Shared entities are common. Unlike a Bazaar
advert, the shared Comcat Advert has no price column and no sold flag, so neither field
is in the mapping or the document.
- Texts are not columns but EAV parameters (
parameterRelsandParameter.key: name, text, keywords, city). They are raw in the database (ContentFilterMode::OnRender), so they are read through the sameAdvert::get($key)as the render, which applies the URL and blacklisted-word replacement. IMPORTANT: callsetRenderBlacklistedWords()with the words of the target language beforeget(), otherwise blacklisted words that the render hides leak into the index. - Visibility is decided by the database (
SearchIdFilterisphaseOneOnly): the filtersactive,expirationDateandconfirmedAtinAdvertListTrait::prepareFilters(). A deleted or banned profile never reaches the index (an emptybuildDocuments()means delete). The Elasticsearch query is additionally pre-narrowed by the same pairactiveandexpirationDate(getVisibilityFilters()), not to replace the database but to keep the relevance path from paging through expired profiles.
Table of Contents
Interfaces
- HighlightableDocumentSourceInterface
- Source that can supply highlighted snippets for search results.
- VisibilityConstrainedDocumentSourceInterface
- Source that can pass its visibility conditions to the ES query.
Constants
- INCLUDES : mixed = ['parameterRels.parameter', 'categoryRels.categ...
- Fetch-join includes: `buildDocuments()` needs the texts (EAV) and the categories.
- KEY : mixed = 'comcat_advert'
Properties
- $blacklistedWordManager : BlacklistedWordManager
- $blacklistedWords : array<int, array<string|int, string>>|null
- $em : EntityManagerInterface
- $languageManager : LanguageManager
- $languages : array<int, string>|null
- $service : AdvertService
Methods
- __construct() : mixed
- buildDocuments() : array<string, array<string, array<string, mixed>>>
- Builds the documents of an entity as `indexBase => (_id => document)`. An empty array means the entity must not be indexed (deactivated or without an active translation), so it is deleted.
- expectedDocumentBounds() : array{min: int, max: int}
- Mirrors the `buildDocuments()` guards: a document exists only for a non-deleted, non-banned profile with an assigned language. The source is single-language, so min equals max (no per-language multiplier as in Blog).
- fetchExistingIds() : array<string|int, int>
- Returns which of the given ids really exist in the DB; orphan cleanup deletes from ES the documents of entities no longer in the DB.
- fetchFresh() : array<int, object>
- Returns fresh entities after commit (service `find` with `useCache: false`). An entity from `completedSave` is not authoritative, because `afterSave` changes the DB through `updateColumn` after the flush. A missing id is omitted.
- fetchIdsChangedSince() : array<string|int, int>
- Returns ids of entities changed or created since `$since` (DB, no cache) as the input of the incremental sync. It must cover both insert and update (`insertTime` or `updateDatetime`); mutations outside the ORM (`updateColumn`, raw SQL) are never covered and the nightly full reindex catches them up.
- fetchReindexBatch() : array<int, object>
- Returns a batch of entities for a full reindex by key: `id > $afterId`, ordered ascending by id, at most `$limit` (with includes, no cache). The array key is the entity id; the last one becomes the cursor the next part of the reindex continues from.
- getAllDocumentIds() : array<string, array<string|int, string>>
- Returns every possible `_id` of the entity across languages as `indexBase => [_id, …]`.
- getEntityIdField() : string
- Returns the ES document field holding the entity id (e.g. `articleId`); sync sorts and pages (`search_after`) by it during the orphan scan.
- getHighlightFields() : array<string, array<int, string>>
- Returns the highlighted snippet fields for `name` and `text`, the title and description the company profile list shows.
- getIndexBaseForLanguage() : string|null
- Returns the index base for a language alias (`cs`), null when the language does not exist.
- getIndexBases() : array<string|int, string>
- Returns index base names without prefix and version; one per language for translated entities (e.g. `['blog_article_cs', 'blog_article_en']`).
- getIndexDefinition() : array<string, mixed>
- Returns the index definition (settings and mappings) for index creation.
- getKey() : string
- Returns the source key for the `enabledSources` allowlist and `EsSearcher`, e.g. `blog_article`.
- getSearchFields() : array<string, int|float>
- Returns the `multi_match` fields with boosts, e.g. `['name' => 3, 'perex' => 2, 'content' => 1]`.
- getVisibilityFilters() : array<int, array<string, mixed>>
- Pre-narrows the Elasticsearch query by visibility.
- getBlacklistedWords() : array<string|int, string>
- Returns the blacklisted words of a language for the render-time replacement (same source as the front end `AdvertDetailTrait::prepareBlacklistedWords()`).
- getLanguages() : array<int, string>
- Returns the language aliases by language id.
- text() : string
- Returns the filtered EAV value of a parameter (same `ParameterContentHelper::apply()` as the render).
- toIds() : array<string|int, int>
Constants
INCLUDES
Fetch-join includes: `buildDocuments()` needs the texts (EAV) and the categories.
private
mixed
INCLUDES
= ['parameterRels.parameter', 'categoryRels.category']
KEY
private
mixed
KEY
= 'comcat_advert'
Properties
$blacklistedWordManager read-only
private
BlacklistedWordManager
$blacklistedWordManager
$blacklistedWords
private
array<int, array<string|int, string>>|null
$blacklistedWords
= null
languageId => blacklisted words (render-time replacement)
$em read-only
private
EntityManagerInterface
$em
$languageManager read-only
private
LanguageManager
$languageManager
$languages
private
array<int, string>|null
$languages
= null
languageId => alias
$service read-only
private
AdvertService
$service
Methods
__construct()
public
__construct(AdvertService $service, LanguageManager $languageManager, BlacklistedWordManager $blacklistedWordManager, EntityManagerInterface $em) : mixed
Parameters
- $service : AdvertService
- $languageManager : LanguageManager
- $blacklistedWordManager : BlacklistedWordManager
- $em : EntityManagerInterface
buildDocuments()
Builds the documents of an entity as `indexBase => (_id => document)`. An empty array means the entity must not be indexed (deactivated or without an active translation), so it is deleted.
public
buildDocuments(object $entity) : array<string, array<string, array<string, mixed>>>
Parameters
- $entity : object
Return values
array<string, array<string, array<string, mixed>>>expectedDocumentBounds()
Mirrors the `buildDocuments()` guards: a document exists only for a non-deleted, non-banned profile with an assigned language. The source is single-language, so min equals max (no per-language multiplier as in Blog).
public
expectedDocumentBounds() : array{min: int, max: int}
Return values
array{min: int, max: int}fetchExistingIds()
Returns which of the given ids really exist in the DB; orphan cleanup deletes from ES the documents of entities no longer in the DB.
public
fetchExistingIds(array<string|int, mixed> $ids) : array<string|int, int>
Parameters
- $ids : array<string|int, mixed>
Return values
array<string|int, int>fetchFresh()
Returns fresh entities after commit (service `find` with `useCache: false`). An entity from `completedSave` is not authoritative, because `afterSave` changes the DB through `updateColumn` after the flush. A missing id is omitted.
public
fetchFresh(array<string|int, mixed> $ids) : array<int, object>
Parameters
- $ids : array<string|int, mixed>
Return values
array<int, object> —keyed by id
fetchIdsChangedSince()
Returns ids of entities changed or created since `$since` (DB, no cache) as the input of the incremental sync. It must cover both insert and update (`insertTime` or `updateDatetime`); mutations outside the ORM (`updateColumn`, raw SQL) are never covered and the nightly full reindex catches them up.
public
fetchIdsChangedSince(DateTimeImmutable $since) : array<string|int, int>
Parameters
- $since : DateTimeImmutable
Return values
array<string|int, int>fetchReindexBatch()
Returns a batch of entities for a full reindex by key: `id > $afterId`, ordered ascending by id, at most `$limit` (with includes, no cache). The array key is the entity id; the last one becomes the cursor the next part of the reindex continues from.
public
fetchReindexBatch(int $afterId, int $limit) : array<int, object>
Parameters
- $afterId : int
- $limit : int
Return values
array<int, object> —keyed by id, ascending
getAllDocumentIds()
Returns every possible `_id` of the entity across languages as `indexBase => [_id, …]`.
public
getAllDocumentIds(int $id) : array<string, array<string|int, string>>
It serves targeted deletion of orphan language documents (orphanRemoval on translations)
and delete; delete_by_query must never be used.
Parameters
- $id : int
Return values
array<string, array<string|int, string>>getEntityIdField()
Returns the ES document field holding the entity id (e.g. `articleId`); sync sorts and pages (`search_after`) by it during the orphan scan.
public
getEntityIdField() : string
Return values
stringgetHighlightFields()
Returns the highlighted snippet fields for `name` and `text`, the title and description the company profile list shows.
public
getHighlightFields() : array<string, array<int, string>>
IMPORTANT: the snippet is built over the indexed text, not the raw database value. EAV
values are raw in the database and the URL/blacklisted-word replacement happens only at
render, so buildDocuments() passes them through the same ParameterContentHelper::apply(); a snippet
built from the database value would leak blacklisted words.
Always both the base field and .folded: the Czech analysis has stopwords and a stemmer,
so a one-word query often matches only .folded.
Return values
array<string, array<int, string>>getIndexBaseForLanguage()
Returns the index base for a language alias (`cs`), null when the language does not exist.
public
getIndexBaseForLanguage(string|null $languageAlias) : string|null
Parameters
- $languageAlias : string|null
Return values
string|nullgetIndexBases()
Returns index base names without prefix and version; one per language for translated entities (e.g. `['blog_article_cs', 'blog_article_en']`).
public
getIndexBases() : array<string|int, string>
Return values
array<string|int, string>getIndexDefinition()
Returns the index definition (settings and mappings) for index creation.
public
getIndexDefinition(string $indexBase) : array<string, mixed>
Parameters
- $indexBase : string
Return values
array<string, mixed>getKey()
Returns the source key for the `enabledSources` allowlist and `EsSearcher`, e.g. `blog_article`.
public
getKey() : string
Return values
stringgetSearchFields()
Returns the `multi_match` fields with boosts, e.g. `['name' => 3, 'perex' => 2, 'content' => 1]`.
public
getSearchFields() : array<string, int|float>
Return values
array<string, int|float>getVisibilityFilters()
Pre-narrows the Elasticsearch query by visibility.
public
getVisibilityFilters() : array<int, array<string, mixed>>
Mirrors exactly what the front end AdvertListTrait::prepareFilters() builds:
EqualFilter('active', true) becomes term active and
DateAfterOrEqualFilter('expirationDate', 'today') becomes a query-time range (NOW()
cannot go into a generated column and a precomputed flag in the index would go stale
every midnight).
NOTE: the active definition differs from Bazaar (no sold), which does not matter here:
the finished value of the generated column is filtered, not its breakdown.
IMPORTANT: the database stays the arbiter, the caller's filters apply on both paths.
confirmedAt is not filtered separately because the generated active already includes it.
Return values
array<int, array<string, mixed>>getBlacklistedWords()
Returns the blacklisted words of a language for the render-time replacement (same source as the front end `AdvertDetailTrait::prepareBlacklistedWords()`).
private
getBlacklistedWords(int $languageId) : array<string|int, string>
Loaded once for all active languages and cached. The cache is assigned only after a successful load: an exception must not leave an empty blacklist.
Parameters
- $languageId : int
Return values
array<string|int, string>getLanguages()
Returns the language aliases by language id.
private
getLanguages() : array<int, string>
The cache is assigned only after a successful load: an exception from findAll() must not
leave the cache "loaded" as empty.
Return values
array<int, string> —languageId => alias
text()
Returns the filtered EAV value of a parameter (same `ParameterContentHelper::apply()` as the render).
private
text(Advert $entity, string $key) : string
get() with alwaysReturnArray unifies single- and multi-valued parameters and applies the
URL and blacklisted-word replacement; the parts are joined into one text.
Parameters
- $entity : Advert
- $key : string
Return values
stringtoIds()
private
toIds(array<string|int, object> $entities) : array<string|int, int>
Parameters
- $entities : array<string|int, object>