*/ private array $entries = []; /** * Next id. * * @var int */ private int $next_id = 1; /** * Constructor. * * @param Clock $clock Clock. */ public function __construct( private readonly Clock $clock, ) {} /** * {@inheritDoc} * * @param int $id Id. */ public function find_by_id( int $id ): ?NotificationLogEntry { return $this->entries[ $id ] ?? null; } /** * {@inheritDoc} * * @param string $key Key. */ public function find_by_idempotency_key( string $key ): ?NotificationLogEntry { foreach ( $this->entries as $entry ) { if ( $entry->idempotency_key() === $key ) { return $entry; } } return null; } /** * {@inheritDoc} * * @param NotificationLogEntry $entry Entry. */ public function save( NotificationLogEntry $entry ): void { if ( null === $entry->id() ) { $entry->assign_id( $this->next_id++ ); } $this->entries[ (int) $entry->id() ] = $entry; } /** * {@inheritDoc} * * @param int $booking_id Booking id. * * @return list */ public function cancel_pending_for_booking( int $booking_id ): array { $cancelled = []; $now = $this->clock->now(); foreach ( $this->entries as $entry ) { if ( $entry->booking_id() !== $booking_id ) { continue; } if ( ! in_array( $entry->status(), [ NotificationStatus::Queued, NotificationStatus::Drafted ], true ) ) { continue; } $entry->mark_cancelled( $now ); $cancelled[] = $entry; } return $cancelled; } /** * {@inheritDoc} * * @param int $booking_id Booking id. * * @return list */ public function pending_for_booking( int $booking_id ): array { $out = []; foreach ( $this->entries as $entry ) { if ( $entry->booking_id() === $booking_id && in_array( $entry->status(), [ NotificationStatus::Queued, NotificationStatus::Drafted ], true ) ) { $out[] = $entry; } } return $out; } /** * {@inheritDoc} * * @param NotificationStatus $status Status. */ public function count_by_status( NotificationStatus $status ): int { $count = 0; foreach ( $this->entries as $entry ) { if ( $entry->status() === $status ) { ++$count; } } return $count; } /** * {@inheritDoc} * * @param array $filters Filters. * @param int $page Page. * @param int $per_page Per page. * * @return array{items: list, total: int} */ public function list_for_admin( array $filters, int $page, int $per_page ): array { $items = array_values( $this->entries ); $status = isset( $filters['status'] ) && is_string( $filters['status'] ) ? trim( $filters['status'] ) : ''; if ( '' !== $status ) { $items = array_values( array_filter( $items, static fn ( NotificationLogEntry $entry ): bool => $entry->status()->value === $status ) ); } $channel = isset( $filters['channel'] ) && is_string( $filters['channel'] ) ? trim( $filters['channel'] ) : ''; if ( '' !== $channel ) { $items = array_values( array_filter( $items, static fn ( NotificationLogEntry $entry ): bool => $entry->channel() === $channel ) ); } $booking_id = isset( $filters['booking_id'] ) ? (int) $filters['booking_id'] : 0; if ( $booking_id > 0 ) { $items = array_values( array_filter( $items, static fn ( NotificationLogEntry $entry ): bool => $entry->booking_id() === $booking_id ) ); } $search = isset( $filters['search'] ) && is_string( $filters['search'] ) ? strtolower( trim( $filters['search'] ) ) : ''; if ( '' !== $search ) { $items = array_values( array_filter( $items, static function ( NotificationLogEntry $entry ) use ( $search ): bool { $hay = strtolower( $entry->recipient() . ' ' . (string) $entry->subject() . ' ' . $entry->template_key() ); return str_contains( $hay, $search ); } ) ); } usort( $items, static function ( NotificationLogEntry $a, NotificationLogEntry $b ): int { return $b->created_at() <=> $a->created_at(); } ); $total = count( $items ); $offset = max( 0, ( $page - 1 ) * $per_page ); return [ 'items' => array_slice( $items, $offset, $per_page ), 'total' => $total, ]; } /** * All entries (tests). * * @return list * * @since 0.1.0 */ public function all(): array { return array_values( $this->entries ); } }