protected $description;
/**
- * List of conflicting groups
+ * Array of associative arrays with conflict information. See
+ * setUnidirectionalConflict
*
- * @var array $conflictingGroups Array of associative arrays with conflict
- * information. See setUnidirectionalConflict
+ * @var array $conflictingGroups
*/
protected $conflictingGroups = [];
/**
- * List of conflicting filters
+ * Array of associative arrays with conflict information. See
+ * setUnidirectionalConflict
*
- * @var array $conflictingFilters Array of associative arrays with conflict
- * information. See setUnidirectionalConflict
+ * @var array $conflictingFilters
*/
protected $conflictingFilters = [];
/**
- * List of filters that are a subset of the current filter
+ * Array of associative arrays with subset information
*
- * @var array $subsetFilters Array of associative arrays with subset information
+ * @var array $subsetFilters
*/
protected $subsetFilters = [];
* UI it's for.
*
* @param array $filterDefinition ChangesListFilter definition
- *
- * $filterDefinition['name'] string Name of filter; use lowercase with no
- * punctuation
- * $filterDefinition['cssClassSuffix'] string CSS class suffix, used to mark
- * that a particular row belongs to this filter (when a row is included by the
- * filter) (optional)
- * $filterDefinition['isRowApplicableCallable'] Callable taking two parameters, the
- * IContextSource, and the RecentChange object for the row, and returning true if
- * the row is attributed to this filter. The above CSS class will then be
- * automatically added (optional, required if cssClassSuffix is used).
- * $filterDefinition['group'] ChangesListFilterGroup Group. Filter group this
- * belongs to.
- * $filterDefinition['label'] string i18n key of label for structured UI.
- * $filterDefinition['description'] string i18n key of description for structured
- * UI.
- * $filterDefinition['priority'] int Priority integer. Higher value means higher
- * up in the group's filter list.
+ * * $filterDefinition['name'] string Name of filter; use lowercase with no
+ * punctuation
+ * * $filterDefinition['cssClassSuffix'] string CSS class suffix, used to mark
+ * that a particular row belongs to this filter (when a row is included by the
+ * filter) (optional)
+ * * $filterDefinition['isRowApplicableCallable'] Callable taking two parameters, the
+ * IContextSource, and the RecentChange object for the row, and returning true if
+ * the row is attributed to this filter. The above CSS class will then be
+ * automatically added (optional, required if cssClassSuffix is used).
+ * * $filterDefinition['group'] ChangesListFilterGroup Group. Filter group this
+ * belongs to.
+ * * $filterDefinition['label'] string i18n key of label for structured UI.
+ * * $filterDefinition['description'] string i18n key of description for structured
+ * UI.
+ * * $filterDefinition['priority'] int Priority integer. Higher value means higher
+ * up in the group's filter list.
*/
public function __construct( array $filterDefinition ) {
if ( isset( $filterDefinition['group'] ) ) {
* @param string $backwardKey i18n key for conflict message in reverse
* direction (when in UI context of $other object)
*/
- public function conflictsWith( $other, $globalKey, $forwardKey,
- $backwardKey ) {
-
- if ( $globalKey === null || $forwardKey === null ||
- $backwardKey === null ) {
-
+ public function conflictsWith( $other, $globalKey, $forwardKey, $backwardKey ) {
+ if ( $globalKey === null || $forwardKey === null || $backwardKey === null ) {
throw new MWException( 'All messages must be specified' );
}
* @param string $contextDescription i18n key for conflict message in this
* direction (when in UI context of $this object)
*/
- public function setUnidirectionalConflict( $other, $globalDescription,
- $contextDescription ) {
-
+ public function setUnidirectionalConflict( $other, $globalDescription, $contextDescription ) {
if ( $other instanceof ChangesListFilterGroup ) {
$this->conflictingGroups[] = [
'group' => $other->getName(),
+ 'groupObject' => $other,
'globalDescription' => $globalDescription,
'contextDescription' => $contextDescription,
];
$this->conflictingFilters[] = [
'group' => $other->getGroup()->getName(),
'filter' => $other->getName(),
+ 'filterObject' => $other,
'globalDescription' => $globalDescription,
'contextDescription' => $contextDescription,
];
* This means that anything in the results for the other filter is also in the
* results for this one.
*
- * @param ChangesListFilter The filter the current instance is a superset of
+ * @param ChangesListFilter $other The filter the current instance is a superset of
*/
public function setAsSupersetOf( ChangesListFilter $other ) {
if ( $other->getGroup() !== $this->getGroup() ) {
*
* @param IContextSource $ctx Context source
* @param RecentChange $rc Recent changes object
- * @param Non-associative array of CSS class names; appended to if needed
+ * @param array &$classes Non-associative array of CSS class names; appended to if needed
*/
public function applyCssClassIfNeeded( IContextSource $ctx, RecentChange $rc, array &$classes ) {
if ( $this->isRowApplicableCallable === null ) {
);
foreach ( $conflicts as $conflictInfo ) {
+ unset( $conflictInfo['filterObject'] );
+ unset( $conflictInfo['groupObject'] );
$output['conflicts'][] = $conflictInfo;
array_push(
$output['messageKeys'],
return $output;
}
+
+ /**
+ * Checks whether this filter is selected in the provided options
+ *
+ * @param FormOptions $opts
+ * @return bool
+ */
+ abstract public function isSelected( FormOptions $opts );
+
+ /**
+ * Get groups conflicting with this filter
+ *
+ * @return ChangesListFilterGroup[]
+ */
+ public function getConflictingGroups() {
+ return array_map(
+ function ( $conflictDesc ) {
+ return $conflictDesc[ 'groupObject' ];
+ },
+ $this->conflictingGroups
+ );
+ }
+
+ /**
+ * Get filters conflicting with this filter
+ *
+ * @return ChangesListFilter[]
+ */
+ public function getConflictingFilters() {
+ return array_map(
+ function ( $conflictDesc ) {
+ return $conflictDesc[ 'filterObject' ];
+ },
+ $this->conflictingFilters
+ );
+ }
+
+ /**
+ * Check if the conflict with a group is currently "active"
+ *
+ * @param ChangesListFilterGroup $group
+ * @param FormOptions $opts
+ * @return bool
+ */
+ public function activelyInConflictWithGroup( ChangesListFilterGroup $group, FormOptions $opts ) {
+ if ( $group->anySelected( $opts ) && $this->isSelected( $opts ) ) {
+ /** @var ChangesListFilter $siblingFilter */
+ foreach ( $this->getSiblings() as $siblingFilter ) {
+ if ( $siblingFilter->isSelected( $opts ) && !$siblingFilter->hasConflictWithGroup( $group ) ) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private function hasConflictWithGroup( ChangesListFilterGroup $group ) {
+ return in_array( $group, $this->getConflictingGroups() );
+ }
+
+ /**
+ * Check if the conflict with a filter is currently "active"
+ *
+ * @param ChangesListFilter $filter
+ * @param FormOptions $opts
+ * @return bool
+ */
+ public function activelyInConflictWithFilter( ChangeslistFilter $filter, FormOptions $opts ) {
+ if ( $this->isSelected( $opts ) && $filter->isSelected( $opts ) ) {
+ /** @var ChangesListFilter $siblingFilter */
+ foreach ( $this->getSiblings() as $siblingFilter ) {
+ if (
+ $siblingFilter->isSelected( $opts ) &&
+ !$siblingFilter->hasConflictWithFilter( $filter )
+ ) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private function hasConflictWithFilter( ChangeslistFilter $filter ) {
+ return in_array( $filter, $this->getConflictingFilters() );
+ }
+
+ /**
+ * Get filters in the same group
+ *
+ * @return ChangesListFilter[]
+ */
+ protected function getSiblings() {
+ return array_filter(
+ $this->getGroup()->getFilters(),
+ function ( $filter ) {
+ return $filter !== $this;
+ }
+ );
+ }
}