*/ private array $items = []; /** * Next id. * * @var int */ private int $next_id = 1; /** * {@inheritDoc} * * @param int $id Id. */ public function find_by_id( int $id ): ?AutomationRun { return $this->items[ $id ] ?? null; } /** * {@inheritDoc} * * @param int $automation_id Automation id. * @param string $trigger_event_id Event id. * @param int $subject_id Subject id. */ public function find_by_dedupe( int $automation_id, string $trigger_event_id, int $subject_id ): ?AutomationRun { foreach ( $this->items as $run ) { if ( $run->automation_id() === $automation_id && $run->trigger_event_id() === $trigger_event_id && $run->subject_id() === $subject_id ) { return $run; } } return null; } /** * {@inheritDoc} * * @param AutomationRun $run Run. */ public function save( AutomationRun $run ): void { $existing = $this->find_by_dedupe( $run->automation_id(), $run->trigger_event_id(), $run->subject_id() ); if ( null !== $existing && null === $run->id() && null !== $existing->id() ) { $run->assign_id( (int) $existing->id() ); } if ( null === $run->id() ) { $run->assign_id( $this->next_id++ ); } $this->items[ (int) $run->id() ] = $run; } /** * {@inheritDoc} * * @param SubjectType $subject_type Subject type. * @param int $subject_id Subject id. * * @return list */ public function find_open_for_subject( SubjectType $subject_type, int $subject_id ): array { $out = []; foreach ( $this->items as $run ) { if ( $run->subject_type() === $subject_type && $run->subject_id() === $subject_id && $run->is_open() ) { $out[] = $run; } } return $out; } /** * {@inheritDoc} * * @param int $customer_id Customer id. * * @return list */ public function find_open_for_customer( int $customer_id ): array { $out = []; foreach ( $this->items as $run ) { if ( $run->customer_id() === $customer_id && $run->is_open() ) { $out[] = $run; } } return $out; } /** * {@inheritDoc} * * @param int $automation_id Automation id. * @param SubjectType $subject_type Subject type. * @param int $subject_id Subject id. */ public function find_latest_counted( int $automation_id, SubjectType $subject_type, int $subject_id ): ?AutomationRun { $latest = null; foreach ( $this->items as $run ) { if ( $run->automation_id() !== $automation_id ) { continue; } if ( $run->subject_type() !== $subject_type || $run->subject_id() !== $subject_id ) { continue; } if ( AutomationRunStatus::Skipped === $run->status() ) { continue; } if ( $run->context()->is_test() ) { continue; } if ( null === $latest || $run->created_at() > $latest->created_at() ) { $latest = $run; } } return $latest; } /** * {@inheritDoc} * * @param int $automation_id Automation id. * @param DateTimeImmutable $since Since. */ public function count_since( int $automation_id, DateTimeImmutable $since ): int { $count = 0; foreach ( $this->items as $run ) { if ( $run->automation_id() !== $automation_id ) { continue; } if ( $run->context()->is_test() ) { continue; } if ( AutomationRunStatus::Skipped === $run->status() ) { continue; } if ( $run->created_at() >= $since ) { ++$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 search( array $filters, int $page, int $per_page ): array { $items = array_values( $this->items ); $aid = isset( $filters['automation_id'] ) ? (int) $filters['automation_id'] : 0; if ( $aid > 0 ) { $items = array_values( array_filter( $items, static fn( AutomationRun $r ): bool => $r->automation_id() === $aid ) ); } $cid = isset( $filters['customer_id'] ) ? (int) $filters['customer_id'] : 0; if ( $cid > 0 ) { $items = array_values( array_filter( $items, static fn( AutomationRun $r ): bool => $r->customer_id() === $cid ) ); } $statuses = []; if ( isset( $filters['statuses'] ) && is_array( $filters['statuses'] ) ) { foreach ( $filters['statuses'] as $piece ) { if ( is_string( $piece ) ) { $enum = AutomationRunStatus::tryFrom( trim( $piece ) ); if ( null !== $enum ) { $statuses[] = $enum; } } } } elseif ( isset( $filters['status'] ) && is_string( $filters['status'] ) && '' !== $filters['status'] ) { if ( 'queue' === $filters['status'] ) { $statuses = [ AutomationRunStatus::Pending, AutomationRunStatus::Running ]; } else { $enum = AutomationRunStatus::tryFrom( $filters['status'] ); if ( null !== $enum ) { $statuses[] = $enum; } } } if ( [] !== $statuses ) { $items = array_values( array_filter( $items, static function ( AutomationRun $r ) use ( $statuses ): bool { return in_array( $r->status(), $statuses, true ); } ) ); } $search = isset( $filters['search'] ) && is_string( $filters['search'] ) ? strtolower( trim( $filters['search'] ) ) : ''; if ( '' !== $search ) { $items = array_values( array_filter( $items, static function ( AutomationRun $r ) use ( $search ): bool { $hay = strtolower( $r->trigger_event_id() . ' ' . $r->subject_type()->value . ' ' . (string) $r->subject_id() ); return str_contains( $hay, $search ); } ) ); } usort( $items, static fn( AutomationRun $a, AutomationRun $b ): int => ( (int) $b->id() ) <=> ( (int) $a->id() ) ); $total = count( $items ); $offset = max( 0, ( $page - 1 ) * $per_page ); $sliced = array_slice( $items, $offset, $per_page ); return [ 'items' => $sliced, 'total' => $total, ]; } /** * All runs (tests). * * @return list * * @since 0.1.0 */ public function all(): array { return array_values( $this->items ); } }