CoolCMS API

AdvertDocumentSource
in package
implements HighlightableDocumentSourceInterface, VisibilityConstrainedDocumentSourceInterface

FinalYes

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 (parameterRels and Parameter.key: name, text, keywords, city). They are raw in the database (ContentFilterMode::OnRender), so they are read through the same Advert::get($key) as the render, which applies the URL and blacklisted-word replacement. IMPORTANT: call setRenderBlacklistedWords() with the words of the target language before get(), otherwise blacklisted words that the render hides leak into the index.
  • Visibility is decided by the database (SearchIdFilter is phaseOneOnly): the filters active, expirationDate and confirmedAt in AdvertListTrait::prepareFilters(). A deleted or banned profile never reaches the index (an empty buildDocuments() means delete). The Elasticsearch query is additionally pre-narrowed by the same pair active and expirationDate (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']

Properties

$blacklistedWords

private array<int, array<string|int, string>>|null $blacklistedWords = null

languageId => blacklisted words (render-time replacement)

Methods

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
string

getHighlightFields()

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

getIndexBases()

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
string

getSearchFields()

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
string

toIds()

private toIds(array<string|int, object> $entities) : array<string|int, int>
Parameters
$entities : array<string|int, object>
Return values
array<string|int, int>
On this page

Search results