answer( $event_id, $event_name, $status, $ticket, $group_by ); } /** * Work out the answer. * * @param int|null $event_id Event ID. * @param string|null $event_name Event title. * @param string|null $status Attendee status. * @param string|null $ticket Ticket type name. * @param string|null $group_by Split. * @return array */ private function answer( ?int $event_id, ?string $event_name, ?string $status, ?string $ticket, ?string $group_by ): array { $check = $this->guard( 'etn_manage_attendee' ); if ( $check ) { return $check; } $page = $this->page( __( 'Attendees', 'aisentic' ), '/attendees' ); $status = trim( (string) $status ); $ticket = trim( (string) $ticket ); $group_by = ( null === $group_by || '' === $group_by ) ? 'none' : $group_by; if ( '' !== $status && ! in_array( $status, self::STATUSES, true ) ) { return $this->unclear( "\"{$status}\" is not an attendee status.", $page, self::STATUSES ); } if ( ! in_array( $group_by, self::GROUPS, true ) ) { return $this->unclear( "Cannot split attendees by \"{$group_by}\".", $page, self::GROUPS ); } list( $event_id, $event_title, $stop ) = $this->resolve_event( $event_id, $event_name, $page ); if ( null !== $stop ) { return $stop; } try { $filters = array_filter( [ 'event_id' => $event_id, 'status' => $status, 'ticket' => $ticket, ] ); $counts = $this->query->count_records( 'attendee', $filters, 'none' === $group_by ? '' : $group_by ); // Zero for a ticket name that does not exist: return the real names instead. // Why: a misheard ticket name gives 0, and "zero" would be a wrong answer. if ( '' !== $ticket && 0 === $counts['total'] ) { $known = $this->ticket_names( $filters ); if ( ! in_array( $ticket, $known, true ) ) { return $this->unclear( "No ticket type is called \"{$ticket}\".", $page, $known ); } } $result = [ 'status' => 'ok', 'total' => $counts['total'], 'filters' => $filters + ( '' !== $event_title ? [ 'event_title' => $event_title ] : [] ), 'page' => $page, ]; if ( 'none' !== $group_by ) { $result += $this->split( $counts['groups'], $group_by ); } return $result; } catch ( \Throwable $e ) { Log::error( 'Eventin_Count_Attendees_Tool error', [ 'error' => $e->getMessage() ] ); return [ 'error' => 'Could not count attendees: ' . $e->getMessage() ]; } } /** * Ticket type names in the same scope, without the ticket filter. * * @param array $filters Filters used for the count. * @return string[] Up to 20 names, most used first. */ private function ticket_names( array $filters ): array { unset( $filters['ticket'], $filters['status'] ); $groups = $this->query->count_records( 'attendee', $filters, 'ticket' )['groups']; return array_slice( array_map( 'strval', array_keys( $groups ) ), 0, 20 ); } /** * Shape the split for the model. * * @param array $groups Raw groups. * @param string $group_by Split. * @return array */ private function split( array $groups, string $group_by ): array { if ( 'status' === $group_by ) { return [ 'by_status' => $groups ]; } list( $kept, $folded, $others ) = $this->top_groups( $groups ); $result = [ 'by_' . $group_by => 'event' === $group_by ? $this->named_event_groups( $kept ) : $kept ]; if ( $folded > 0 ) { $result[ 'other_' . $group_by . 's' ] = [ 'groups' => $folded, 'attendees' => $others, 'note' => 'Only the 10 largest are listed.', ]; } return $result; } }