Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
28 / 28
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
HideUserUtils
100.00% covered (success)
100.00%
28 / 28
100.00% covered (success)
100.00%
2 / 2
3
100.00% covered (success)
100.00%
1 / 1
 getExpression
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
2
 addFieldToBuilder
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace MediaWiki\Block;
4
5use Wikimedia\Rdbms\IReadableDatabase;
6use Wikimedia\Rdbms\SelectQueryBuilder;
7
8/**
9 * Helpers for building queries that determine whether a user is hidden
10 * @since 1.42
11 */
12class HideUserUtils {
13    /**
14     * Select users that are not hidden
15     */
16    public const SHOWN_USERS = 1;
17
18    /**
19     * Select users that are hidden
20     */
21    public const HIDDEN_USERS = 2;
22
23    /**
24     * Get an SQL expression suitable for use in WHERE clause which will be
25     * true for either hidden or non-hidden users as specified.
26     *
27     * The expression will contain a subquery.
28     *
29     * @param IReadableDatabase $dbr
30     * @param string $userIdField The field to be used as the user_id when
31     *   joining on block. Defaults to "user_id".
32     * @param int $status Either self::SHOWN_USERS or self::HIDDEN_USERS
33     *   depending on what sort of user you want to match.
34     * @return string
35     */
36    public function getExpression(
37        IReadableDatabase $dbr,
38        string $userIdField = 'user_id',
39        $status = self::SHOWN_USERS
40    ) {
41        // Use a scalar subquery, not IN/EXISTS, to avoid materialization (T360160)
42        return '(' .
43            $dbr->newSelectQueryBuilder()
44                ->select( '1' )
45                // $userIdField may be e.g. block_target.bt_user so an inner table
46                // alias is necessary to ensure that that refers to the outer copy
47                // of the block_target table.
48                ->from( 'block_target', 'hu_block_target' )
49                ->join( 'block', 'hu_block', 'hu_block.bl_target=hu_block_target.bt_id' )
50                ->where( [ "hu_block_target.bt_user=$userIdField", 'hu_block.bl_deleted' => 1 ] )
51                ->limit( 1 )
52                ->caller( __METHOD__ )
53                ->getSQL() .
54            ') ' .
55            ( $status === self::HIDDEN_USERS ? 'IS NOT NULL' : 'IS NULL' );
56    }
57
58    /**
59     * Add a field and related joins to the query builder. The field in the
60     * query result will be true if the user is hidden or false otherwise.
61     *
62     * @param SelectQueryBuilder $qb The query builder to be modified
63     * @param string $userIdField The name of the user_id field to use in the join
64     * @param string $deletedFieldAlias The field alias which will be true if the user is hidden.
65     */
66    public function addFieldToBuilder(
67        SelectQueryBuilder $qb,
68        $userIdField = 'user_id',
69        $deletedFieldAlias = 'hu_deleted'
70    ) {
71        $cond = '(' .
72            $qb->newSubquery()
73                ->select( '1' )
74                // $userIdField may be e.g. block_target.bt_user so an inner table
75                // alias is necessary to ensure that that refers to the outer copy
76                // of the block_target table.
77                ->from( 'block_target', 'hu_block_target' )
78                ->join( 'block', 'hu_block', 'hu_block.bl_target=hu_block_target.bt_id' )
79                ->where( [ "hu_block_target.bt_user=$userIdField", 'hu_block.bl_deleted' => 1 ] )
80                ->limit( 1 )
81                ->caller( __METHOD__ )
82                ->getSQL() .
83            ') IS NOT NULL';
84        $qb->select( [ $deletedFieldAlias => $cond ] );
85    }
86}