Skip to main content

MembershipTierRepository

\Benecaster\Membership\MembershipTierRepository

Class Premium

Data access for the tiers sold by the built-in membership system. A tier is a name, a slug, a trial length, a description, an active flag, and a collection of billing cadences.

The cadences are a separate collection reached through MembershipPriceRepository, which this class takes as an optional constructor dependency and cascades through. Reads and writes both accept and return a prices[] sub-array, so most callers never touch the price repository directly.

Constructor Dependencies

Type Description
\Benecaster\Membership\MembershipPriceRepository Optional. Supplied by the container in normal operation; when omitted the tier repository still reads and writes tier rows but will not cascade to prices.

Methods

Method Visibility Since Description
insert( array $tier ): int Public — Creates a tier and returns its ID. A prices[] sub-array is cascade-inserted through MembershipPriceRepository, so a tier and all its cadences can be created in one call.
update( int $tier_id, array $tier ): bool Public — Updates a tier. A prices[] sub-array is reconciled rather than replaced — rows present in the payload with an ID are updated, rows without one are inserted, and stored rows absent from the payload are deleted. Omit prices[] entirely to leave the cadences untouched.
delete( int $tier_id ): bool Public — Deletes a tier and cascades delete_by_tier() so no cadences are orphaned.
ranked_slugs( int $show_id ): list<string> Public — Returns the show's tier slugs, lowest rank first, in the same ORDER BY tier_order ASC, id ASC as find_by_show() — one query, no price hydration. This is the position-based ranking [benecaster_tier_gate] compares against, not the raw tier_order value: every admin-created built-in tier stores tier_order = 0, so comparing values directly would admit every tier.

Hooks Fired

Notes

Every tier write fires benecaster_clear_feed_cache for the show — insert(), delete(), delete_by_show(), and any update() touching a column other than a tier's Stripe product IDs. The tier table is not part of the feed cache key, so without this a tier reorder or rename would otherwise leave stale tier-dependent feed XML cached for up to a day.

Legacy price fields are synthesised on read and are read-only. Tier rows returned from this repository still carry monthly_price, annual_price, and the four stripe_{monthly,annual}_price_id_{test,live} keys, derived from the prices[] collection by matching month × 1 and year × 1.

They are a view, not storage. Writing to them does nothing — a tier update that sets monthly_price and omits prices[] will not change any price. Use the prices[] array, or MembershipPriceRepository directly.

They also cannot describe a tier accurately once it sells anything other than monthly and annual. A tier with a quarterly cadence reports null for both legacy fields if it has no month × 1 or year × 1 row. Any code that still branches on monthly_price should be migrated to iterate prices[].