$product Product. * @param mixed $keys Candidate keys. * @return list */ public static function clean( array $product, $keys ): array { $keys = is_array( $keys ) ? array_map( 'strval', $keys ) : array(); return array_values( array_intersect( array_keys( $product['audiences'] ), $keys ) ); } /** * The current choice of a user for a product ([] = everyone). * * @param int $user_id User. * @param array $product Product. * @return list */ public static function selected( int $user_id, array $product ): array { if ( array() === $product['audiences'] ) { return array(); } return self::clean( $product, Prefs::get( $user_id, Prefs::AUDIENCES, $product['slug'], array() ) ); } /** * Whether an entry with these audiences shows for the choice: always for everyone ([]) and for a persona that * sees all; else when the lists meet. * * @param array $product Product. * @param string[] $audiences Entry audiences. * @param string[] $selected The choice. */ public static function matches( array $product, array $audiences, array $selected ): bool { if ( array() === $selected ) { return true; } foreach ( $selected as $key ) { if ( ! empty( $product['audiences'][ $key ]['all'] ) ) { return true; } } return array() !== array_intersect( $audiences, $selected ); } /** * The sections for a choice: `core` = the sections with at least one entry of the chosen roles, product order; * `folded` = the others, which the menu bar folds into "Everything else" and Home lists collapsed. The section * being viewed is never folded; a choice that matches nothing folds nothing. * * @param array $product Product. * @param array>> $by Entries by section. * @param string[] $selected The choice. * @param string $keep Section never folded ('' = none). * @return array{core: list, folded: list} */ public static function sections( array $product, array $by, array $selected, string $keep = '' ): array { if ( array() === $selected ) { return array( 'core' => array_keys( $by ), 'folded' => array(), ); } $core = array(); $folded = array(); $hit = false; foreach ( $by as $key => $entries ) { $match = false; foreach ( $entries as $entry ) { if ( self::matches( $product, (array) $entry['audiences'], $selected ) ) { $match = true; break; } } $hit = $hit || $match; if ( $match || $key === $keep ) { $core[] = (string) $key; } else { $folded[] = (string) $key; } } if ( ! $hit ) { return array( 'core' => array_keys( $by ), 'folded' => array(), ); } return array( 'core' => $core, 'folded' => $folded, ); } }