MembershipTierRepository
\Benecaster\Membership\MembershipTierRepository
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[].