CoolCMS API

QueryPathPolicy
in package

FinalYes

Restricts the field paths in `filters` / `orderBys` / `columns` to fields the caller would also receive in the output.

FieldAccess and PersonalData filter only the emitted payload, but a where clause is an equally good channel: filters[...][field]=user.password with a like start match returns a record or nothing, which allows reconstructing a password hash, salt or confirming someone else's e-mail character by character. Ordering by a hidden field leaks the same through the order.

An unprivileged caller (same decision as the emit, FieldAudienceContext::allows()) may use only path segments that are mapped fields or associations of the entity and have no read audience that would withhold the field from the output, and no PersonalData. A privileged caller (admin) and an unknown audience (cron, CLI) pass unchanged.

Ready-made Filter objects are not checked: from the wire only arrays arrive, and objects are built by server PHP code, which chooses its fields itself.

An unknown segment (typo, nonexistent field) is rejected on the external path, otherwise it would end in a Doctrine exception (HTTP 500); on the internal path it passes, so front end behavior is unchanged.

columns goes into DQL verbatim (alias.<column>), so an external caller may send only the bare name of a mapped field of the root entity.

Table of Contents

Constants

GROUP_TYPES  : array<string|int, mixed> = ['group', 'or', 'and']
Types whose `filters` carry nested definitions (same as `FilterBuilder`).
LANGUAGE_SCOPED  : string = '/^([A-Za-z_][A-Za-z0-9_]*)\[languageId:\d+\]\....
`translations[languageId:2].name`: ordering by a translation in one language.
PLAIN_FIELD  : string = '/^[A-Za-z_][A-Za-z0-9_]*$/'
Bare field name; anything else in `columns` from the wire is suspicious.

Properties

$audience  : FieldAudienceContext
$em  : EntityManagerInterface
$rulesCache  : array<string, array<string, Audience, 1: bool}>>

Methods

__construct()  : mixed
findDeniedPath()  : string|null
Returns the first denied path, or `null` when everything is allowed.
isPathAllowed()  : bool
Returns whether an unprivileged caller may use this dotted path on the entity.
collectRules()  : array<string, Audience, 1: bool}>
filterPaths()  : array<int, string>
Collects all field paths from the filter definition arrays (recursively through groups).
hasPolicyAttribute()  : bool
isHidden()  : bool
Returns whether the field would be withheld from an unprivileged caller in the output (`FieldAccess` read / `PersonalData`).
orderByPath()  : string|null
Returns the field path from an ordering key ({@see OrderByHelper::addOrderBys()}); `null` is a virtual key without an entity field (current price in a currency).

Constants

GROUP_TYPES

Types whose `filters` carry nested definitions (same as `FilterBuilder`).

private array<string|int, mixed> GROUP_TYPES = ['group', 'or', 'and']

LANGUAGE_SCOPED

`translations[languageId:2].name`: ordering by a translation in one language.

private string LANGUAGE_SCOPED = '/^([A-Za-z_][A-Za-z0-9_]*)\[languageId:\d+\]\.([A-Za-z_][A-Za-z0-9_]*)$/'

PLAIN_FIELD

Bare field name; anything else in `columns` from the wire is suspicious.

private string PLAIN_FIELD = '/^[A-Za-z_][A-Za-z0-9_]*$/'

Properties

$rulesCache

private array<string, array<string, Audience, 1: bool}>> $rulesCache = []

class => field => [read audience, personal data]

Methods

findDeniedPath()

Returns the first denied path, or `null` when everything is allowed.

public findDeniedPath(string $entityClass, array<string|int, mixed> $filters[, array<string|int, mixed>|null $orderBys = null ][, array<string|int, mixed>|null $columns = null ][, bool $external = true ]) : string|null
Parameters
$entityClass : string
$filters : array<string|int, mixed>

filter definitions (arrays and ready-made objects)

$orderBys : array<string|int, mixed>|null = null

field => direction

$columns : array<string|int, mixed>|null = null
$external : bool = true

external HTTP: unknown segments and non-bare columns are rejected

Return values
string|null

isPathAllowed()

Returns whether an unprivileged caller may use this dotted path on the entity.

public isPathAllowed(string $entityClass, string $path[, bool $external = true ]) : bool
Parameters
$entityClass : string
$path : string
$external : bool = true
Return values
bool

collectRules()

private static collectRules(string $class) : array<string, Audience, 1: bool}>
Parameters
$class : string
Return values
array<string, Audience, 1: bool}> —

field => [read audience, personal data]

filterPaths()

Collects all field paths from the filter definition arrays (recursively through groups).

private filterPaths(array<string|int, mixed> $filters) : array<int, string>
Parameters
$filters : array<string|int, mixed>
Return values
array<int, string>

hasPolicyAttribute()

private static hasPolicyAttribute(ReflectionProperty $property) : bool
Parameters
$property : ReflectionProperty
Return values
bool

isHidden()

Returns whether the field would be withheld from an unprivileged caller in the output (`FieldAccess` read / `PersonalData`).

private isHidden(ClassMetadata<string|int, object> $metadata, string $field) : bool
Parameters
$metadata : ClassMetadata<string|int, object>
$field : string
Return values
bool

orderByPath()

Returns the field path from an ordering key ({@see OrderByHelper::addOrderBys()}); `null` is a virtual key without an entity field (current price in a currency).

private static orderByPath(string $key) : string|null
Parameters
$key : string
Return values
string|null
On this page

Search results