schedules = $schedules; $this->controller = $controller; } /** * Whether the current user can see the card. * * @return bool */ public function can_view(): bool { return current_user_can( ScheduledElementsController::CAPABILITY ); } /** * The card's data: counts by status, one page of active and upcoming * schedules, and the screen's address. * * @param int $page Page number, from 1. * @param int $per_page Items per page. * @param int|null $now UTC timestamp; now by default. * @return array{counts: array{active: int, upcoming: int, ended: int}, total: int, page: int, pages: int, items: array>, screenUrl: string} */ public function data( int $page = 1, int $per_page = self::CARD_ITEMS, ?int $now = null ): array { $now = $now ?? time(); $counts = array( ScheduledElements::ACTIVE => 0, ScheduledElements::UPCOMING => 0, ScheduledElements::ENDED => 0, ); $listed = array(); foreach ( $this->schedules->all() as $schedule ) { if ( ! $schedule['enabled'] ) { continue; } $status = ScheduledElements::status( $schedule, $now ); ++$counts[ $status ]; if ( ScheduledElements::ENDED !== $status ) { $listed[] = $schedule + array( '_status' => $status ); } } usort( $listed, array( $this, 'compare' ) ); $per_page = max( 1, $per_page ); $pages = (int) max( 1, ceil( count( $listed ) / $per_page ) ); $page = min( max( 1, $page ), $pages ); $items = array(); foreach ( array_slice( $listed, ( $page - 1 ) * $per_page, $per_page ) as $schedule ) { unset( $schedule['_status'] ); $items[] = $this->controller->prepare( $schedule ); } return array( 'counts' => $counts, 'total' => count( $listed ), 'page' => $page, 'pages' => $pages, 'items' => $items, 'screenUrl' => admin_url( 'admin.php?page=' . ScheduledElementsPage::SLUG ), ); } /** * Active schedules first (soonest to end first, never-ending last), then * upcoming ones (soonest to start first). * * @param array $a Schedule with `_status`. * @param array $b Schedule with `_status`. * @return int */ private function compare( array $a, array $b ): int { return array( $this->rank( $a ), $this->next_change( $a ) ) <=> array( $this->rank( $b ), $this->next_change( $b ) ); } /** * 0 for active, 1 for upcoming. * * @param array $schedule Schedule with `_status`. * @return int */ private function rank( array $schedule ): int { return ScheduledElements::ACTIVE === $schedule['_status'] ? 0 : 1; } /** * When the schedule next changes: its hide time while active, its show * time while upcoming. No end sorts last. * * @param array $schedule Schedule with `_status`. * @return int */ private function next_change( array $schedule ): int { $time = ScheduledElements::ACTIVE === $schedule['_status'] ? $schedule['hide_at'] : $schedule['show_at']; return null === $time ? PHP_INT_MAX : (int) $time; } }