phpbotgram

ChatMemberUpdatedFilter extends Filter
in package

FinalYes

Dispatcher-side filter that matches a `ChatMemberUpdated` event by comparing the wire-level statuses of `old_chat_member` and `new_chat_member`.

Port of aiogram.filters.chat_member_updated.ChatMemberUpdatedFilter (aiogram/filters/chat_member_updated.py:192-219).

Aiogram DSL → PHP factories

Upstream exposes a Python-only operator DSL on _MemberStatusMarker instances:

KICKED | LEFT >> +MEMBER # was kicked/left, now member JOIN_TRANSITION = IS_NOT_MEMBER >> IS_MEMBER LEAVE_TRANSITION = ~JOIN_TRANSITION PROMOTED_TRANSITION = (MEMBER | RESTRICTED | LEFT | KICKED) >> ADMINISTRATOR

PHP can't reuse | / >> / ~ between class instances (operator overloading is limited to a handful of arithmetic methods on numeric objects via Pure\Math). The port replaces the operator DSL with THREE factory shapes matching upstream's three rule shapes:

  1. newStatus(array $statuses) — constrain only the NEW status (wildcard old side). Mirrors upstream's _MemberStatusMarker / _MemberStatusGroupMarker single-axis rule. Internally stored as new self([], $statuses) where oldStatuses = [] signals "match any".

  2. transition(array $from, array $to) / direct constructor: explicit oldStatuses AND newStatuses. Mirrors upstream's _MemberStatusTransition old/new rule.

  3. Named pre-built factories — join(), leave(), promotion(), demotion() — mirroring upstream's JOIN_TRANSITION / LEAVE_TRANSITION / PROMOTED_TRANSITION constants and a reverse-promotion pre-built. The +/- is_member modifier on RESTRICTED (upstream's IS_MEMBER includes +RESTRICTED, IS_NOT_MEMBER includes -RESTRICTED) is collapsed: restricted users count as members for the named factories. Callers that need the finer-grained is_member gate can build a transition by hand and post-filter on oldChatMember->isMember / newChatMember->isMember via a Logic AND combinator.

Reading status off ChatMember

The abstract ChatMember parent does NOT declare a status property — each concrete subclass (ChatMemberOwner, ChatMemberAdministrator, ChatMemberMember, ChatMemberRestricted, ChatMemberLeft, ChatMemberBanned) carries its own public readonly string $status defaulted to the discriminator value. The filter resolves the wire string via a static match-on-class helper so PHPStan level 9 stays happy without a @property declaration on the abstract parent.

Return shape

Pure bool. The filter contributes no kwargs to the handler — upstream's __call__ returns plain bool for matching/non-matching transitions.

Table of Contents

Constants

ADMINISTRATOR  : array<string|int, mixed> = ['administrator']
CREATOR  : array<string|int, mixed> = ['creator']
Singleton-status sets. The names mirror upstream's `_MemberStatusMarker` instances at `chat_member_updated.py:176-181`, exposed here as `list<string>` so they slot directly into the constructor's `oldStatuses` / `newStatuses` parameters.
IS_ADMIN  : array<string|int, mixed> = ['creator', 'administrator']
Statuses with elevated privileges. Mirrors upstream's `IS_ADMIN = CREATOR | ADMINISTRATOR` at `chat_member_updated.py:184`.
IS_MEMBER  : array<string|int, mixed> = ['creator', 'administrator', 'member', 'restric...
Statuses representing "currently in the chat". Mirrors upstream's `IS_MEMBER = CREATOR | ADMINISTRATOR | MEMBER | +RESTRICTED` at `chat_member_updated.py:183`. The `+RESTRICTED` nuance (only restricted users with `is_member=True` are members) is collapsed — see class docblock for the workaround.
IS_NOT_MEMBER  : array<string|int, mixed> = ['left', 'kicked']
Statuses representing "not in the chat". Mirrors upstream's `IS_NOT_MEMBER = LEFT | KICKED | -RESTRICTED` at `chat_member_updated.py:185`. Same `-RESTRICTED` collapse caveat.
KICKED  : array<string|int, mixed> = ['kicked']
LEFT  : array<string|int, mixed> = ['left']
MEMBER  : array<string|int, mixed> = ['member']
RESTRICTED  : array<string|int, mixed> = ['restricted']

Properties

$newStatuses  : array<string|int, mixed>
$oldStatuses  : array<string|int, mixed>

Methods

__construct()  : mixed
__invoke()  : array<string, mixed>|bool
Evaluate the filter against an update.
all()  : AndFilter
Compose an AND across filters: every child must accept, kwargs cascade. PHP equivalent of Python's `f1 & f2`.
any()  : OrFilter
Compose an OR across filters: the first accepting child wins, no cascade. PHP equivalent of Python's `f1 | f2`.
demotion()  : self
Pre-built `IS_ADMIN → MEMBER`. Symmetric inverse of `promotion()`. No upstream constant — falls out of the marker DSL naturally (`ADMINISTRATOR >> MEMBER` etc).
invertOf()  : InvertFilter
Invert a filter's accept/reject decision. Named `invertOf` rather than `not` because PHP forbids a static and an instance method sharing one name in a single class (the instance-side `$f->not()` convenience may land in a later task).
join()  : self
Pre-built `IS_NOT_MEMBER → IS_MEMBER`. Mirrors upstream's `JOIN_TRANSITION` constant at `chat_member_updated.py:187`. Matches a user (re)joining the chat — left/kicked → creator/administrator/ member/restricted.
leave()  : self
Pre-built `IS_MEMBER → IS_NOT_MEMBER`. Mirrors upstream's `LEAVE_TRANSITION = ~JOIN_TRANSITION` at `chat_member_updated.py:188`.
newStatus()  : self
Constrain only the NEW status (wildcard old side). Mirrors upstream's `_MemberStatusMarker` / `_MemberStatusGroupMarker` single-axis rule shape — the first of upstream's three rule shapes. Passing `oldStatuses = []` signals "match any old status" inside `__invoke`.
promotion()  : self
Pre-built `MEMBER → IS_ADMIN`. Narrower than upstream's `PROMOTED_TRANSITION = (MEMBER | RESTRICTED | LEFT | KICKED) >> ADMINISTRATOR` (`chat_member_updated.py:189`) — we restrict the source to a plain `MEMBER` so `promotion()` and `demotion()` stay symmetric. Callers needing the wider upstream rule can call `transition()` directly.
transition()  : self
Build a transition rule from arbitrary old/new status sets. Equivalent to the constructor but reads declaratively at call sites:
statusOf()  : string
Resolve the wire-level `status` string for a `ChatMember` union value.

Constants

CREATOR

Singleton-status sets. The names mirror upstream's `_MemberStatusMarker` instances at `chat_member_updated.py:176-181`, exposed here as `list<string>` so they slot directly into the constructor's `oldStatuses` / `newStatuses` parameters.

public array<string|int, mixed> CREATOR = ['creator']

IS_ADMIN

Statuses with elevated privileges. Mirrors upstream's `IS_ADMIN = CREATOR | ADMINISTRATOR` at `chat_member_updated.py:184`.

public array<string|int, mixed> IS_ADMIN = ['creator', 'administrator']

IS_MEMBER

Statuses representing "currently in the chat". Mirrors upstream's `IS_MEMBER = CREATOR | ADMINISTRATOR | MEMBER | +RESTRICTED` at `chat_member_updated.py:183`. The `+RESTRICTED` nuance (only restricted users with `is_member=True` are members) is collapsed — see class docblock for the workaround.

public array<string|int, mixed> IS_MEMBER = ['creator', 'administrator', 'member', 'restricted']

IS_NOT_MEMBER

Statuses representing "not in the chat". Mirrors upstream's `IS_NOT_MEMBER = LEFT | KICKED | -RESTRICTED` at `chat_member_updated.py:185`. Same `-RESTRICTED` collapse caveat.

public array<string|int, mixed> IS_NOT_MEMBER = ['left', 'kicked']

Properties

Methods

__construct()

public __construct(array<int, string> $oldStatuses, array<int, string> $newStatuses) : mixed
Parameters
$oldStatuses : array<int, string>

Accepted statuses for old_chat_member.

$newStatuses : array<int, string>

Accepted statuses for new_chat_member.

__invoke()

Evaluate the filter against an update.

public __invoke(object $event, mixed ...$kwargs) : array<string, mixed>|bool
Parameters
$event : object
$kwargs : mixed

Dispatcher kwargs bag — captured variadically so the full bag passes through CallableObject::prepareKwargs. Unused by this filter (event-only decision).

Return values
array<string, mixed>|bool

See class docblock for the interpretation contract.

all()

Compose an AND across filters: every child must accept, kwargs cascade. PHP equivalent of Python's `f1 & f2`.

public static all(Filter ...$filters) : AndFilter
Parameters
$filters : Filter
Return values
AndFilter

any()

Compose an OR across filters: the first accepting child wins, no cascade. PHP equivalent of Python's `f1 | f2`.

public static any(Filter ...$filters) : OrFilter
Parameters
$filters : Filter
Return values
OrFilter

demotion()

Pre-built `IS_ADMIN → MEMBER`. Symmetric inverse of `promotion()`. No upstream constant — falls out of the marker DSL naturally (`ADMINISTRATOR >> MEMBER` etc).

public static demotion() : self
Return values
self

invertOf()

Invert a filter's accept/reject decision. Named `invertOf` rather than `not` because PHP forbids a static and an instance method sharing one name in a single class (the instance-side `$f->not()` convenience may land in a later task).

public static invertOf(Filter $filter) : InvertFilter
Parameters
$filter : Filter
Return values
InvertFilter

join()

Pre-built `IS_NOT_MEMBER → IS_MEMBER`. Mirrors upstream's `JOIN_TRANSITION` constant at `chat_member_updated.py:187`. Matches a user (re)joining the chat — left/kicked → creator/administrator/ member/restricted.

public static join() : self
Return values
self

leave()

Pre-built `IS_MEMBER → IS_NOT_MEMBER`. Mirrors upstream's `LEAVE_TRANSITION = ~JOIN_TRANSITION` at `chat_member_updated.py:188`.

public static leave() : self

Matches a user voluntarily leaving or being kicked/banned.

Return values
self

newStatus()

Constrain only the NEW status (wildcard old side). Mirrors upstream's `_MemberStatusMarker` / `_MemberStatusGroupMarker` single-axis rule shape — the first of upstream's three rule shapes. Passing `oldStatuses = []` signals "match any old status" inside `__invoke`.

public static newStatus(array<int, string> $statuses) : self

Example — match any member who becomes an administrator, regardless of their previous status:

ChatMemberUpdatedFilter::newStatus(ChatMemberUpdatedFilter::ADMINISTRATOR)

Parameters
$statuses : array<int, string>

The accepted statuses for new_chat_member.

Return values
self

promotion()

Pre-built `MEMBER → IS_ADMIN`. Narrower than upstream's `PROMOTED_TRANSITION = (MEMBER | RESTRICTED | LEFT | KICKED) >> ADMINISTRATOR` (`chat_member_updated.py:189`) — we restrict the source to a plain `MEMBER` so `promotion()` and `demotion()` stay symmetric. Callers needing the wider upstream rule can call `transition()` directly.

public static promotion() : self
Return values
self

transition()

Build a transition rule from arbitrary old/new status sets. Equivalent to the constructor but reads declaratively at call sites:

public static transition(array<int, string> $from, array<int, string> $to) : self

ChatMemberUpdatedFilter::transition( from: ChatMemberUpdatedFilter::IS_NOT_MEMBER, to: ChatMemberUpdatedFilter::MEMBER, );

Parameters
$from : array<int, string>
$to : array<int, string>
Return values
self

statusOf()

Resolve the wire-level `status` string for a `ChatMember` union value.

private static statusOf(ChatMember $member) : string

The abstract ChatMember parent doesn't declare status — each concrete subclass carries its own public readonly string $status defaulted to its discriminator. PHPStan level 9 won't accept $member->status on an abstract typed variable; the match over concrete classes gives the static analyser the discriminator without runtime reflection. Mirrors upstream's getattr(member, "status", None) indirection at chat_member_updated.py:89 but without the None fallback because every constructible ChatMember subclass in the regenerated types module declares a non-null status.

Parameters
$member : ChatMember
Return values
string
On this page

Search results