CoolCMS API

CategoryRelsPaidSanitizationTrait

Server-side sanitization of `paid` on hydrated `categoryRels` on the external path.

IMPORTANT: categoryRels goes through the object-graph persist, so paid is a scalar that an external client (data.categoryRels[].paid) may send freely and the hydrator writes it. A third party could then mark its own advert as paid without a real payment (paid drives the payment/visibility flow, see PaymentItemManager).

$meta['__external'] (set by SaveTrait::actionSave) separates external writes from the internal admin/front path; only external writes are overwritten (admin may set paid from the form). The hydrated $advert->getCategoryRels() is rewritten in beforeSave (before flush) and DB values are read with raw DBAL, because find()/findAll() would detach the merged graph via GetAllTrait::clearDoctrine().

Rules per rel:

  • existing rel (advertId + categoryId in the DB): the DB paid is kept; an external update can neither set nor reset it.
  • new rel: paid is derived like on the front insert-only path AdvertRelSyncTrait::syncCategoryRels, from Category::getForFree(). AdvertRelSyncTrait::syncCategoryRels: Category::getForFree() (free category is displayable at once, paid one waits for payment).
Tags
requires

AdvertManager expects:

  • $em (EntityManagerInterface) — raw DBAL connection

Table of Contents

Methods

sanitizedCategoryRelPaid()  : bool
Pure (stateless) sanitization derivation, extracted so it is testable without a DB.
fetchCategoryForFreeMap()  : array<int, bool>
Raw DBAL: reads `Category::getForFree()` (column `for_free`) for the given categories.
fetchExistingCategoryRelPaidMap()  : array<int, bool>
Raw DBAL: reads `paid` of already existing rel rows (advertId + categoryId), i.e. the pre-save DB state (`beforeSave` runs before flush). Empty on insert (advertId null) and without categories.
sanitizeExternalCategoryRelsPaid()  : void
Entry point called from `beforeSave`. No-op on the internal path (marker missing) and when the `categoryRels` collection is empty (the external client sent no such key).

Methods

sanitizedCategoryRelPaid()

Pure (stateless) sanitization derivation, extracted so it is testable without a DB.

public static sanitizedCategoryRelPaid(int $categoryId, array<int, bool> $existingPaidByCategoryId, array<int, bool> $forFreeByCategoryId) : bool
Parameters
$categoryId : int
$existingPaidByCategoryId : array<int, bool>

(a) DB paid for already existing rels

$forFreeByCategoryId : array<int, bool>

(b) Category::getForFree() for new rels

Return values
bool

fetchCategoryForFreeMap()

Raw DBAL: reads `Category::getForFree()` (column `for_free`) for the given categories.

private fetchCategoryForFreeMap(array<string|int, int> $categoryIds) : array<int, bool>
Parameters
$categoryIds : array<string|int, int>
Return values
array<int, bool> —

categoryId => for_free

fetchExistingCategoryRelPaidMap()

Raw DBAL: reads `paid` of already existing rel rows (advertId + categoryId), i.e. the pre-save DB state (`beforeSave` runs before flush). Empty on insert (advertId null) and without categories.

private fetchExistingCategoryRelPaidMap(int|null $advertId, array<string|int, int> $categoryIds) : array<int, bool>
Parameters
$advertId : int|null
$categoryIds : array<string|int, int>
Return values
array<int, bool> —

categoryId => DB paid

sanitizeExternalCategoryRelsPaid()

Entry point called from `beforeSave`. No-op on the internal path (marker missing) and when the `categoryRels` collection is empty (the external client sent no such key).

private sanitizeExternalCategoryRelsPaid(Advert $advert, array<string, mixed> $meta) : void
Parameters
$advert : Advert
$meta : array<string, mixed>
On this page

Search results