40 private const TYPES_MAP = [
41 PageRestriction::TYPE_ID => PageRestriction::class,
42 NamespaceRestriction::TYPE_ID => NamespaceRestriction::class,
43 ActionRestriction::TYPE_ID => ActionRestriction::class,
49 private $loadBalancer;
62 $wikiId = WikiAwareEntity::LOCAL
64 $this->loadBalancer = $loadBalancer;
65 $this->wikiId = $wikiId;
76 if ( $blockId ===
null || $blockId === [] ) {
80 $db = $this->loadBalancer->getConnectionRef(
DB_REPLICA, [], $this->wikiId );
82 $result = $db->select(
83 [
'ipblocks_restrictions',
'page' ],
84 [
'ir_ipb_id',
'ir_type',
'ir_value',
'page_namespace',
'page_title' ],
85 [
'ir_ipb_id' => $blockId ],
88 [
'page' => [
'LEFT JOIN', [
'ir_type' => PageRestriction::TYPE_ID,
'ir_value=page_id' ] ] ]
91 return $this->resultToRestrictions( $result );
101 public function insert( array $restrictions ) {
102 if ( !$restrictions ) {
107 foreach ( $restrictions as $restriction ) {
111 $rows[] = $restriction->toRow();
118 $dbw = $this->loadBalancer->getConnectionRef(
DB_PRIMARY, [], $this->wikiId );
121 'ipblocks_restrictions',
138 public function update( array $restrictions ) {
139 $dbw = $this->loadBalancer->getConnectionRef(
DB_PRIMARY, [], $this->wikiId );
141 $dbw->startAtomic( __METHOD__ );
144 $restrictionList = $this->restrictionsByBlockId( $restrictions );
151 $blockIds = array_keys( $restrictionList );
152 if ( !empty( $blockIds ) ) {
153 $result = $dbw->select(
154 [
'ipblocks_restrictions' ],
155 [
'ir_ipb_id',
'ir_type',
'ir_value' ],
156 [
'ir_ipb_id' => $blockIds ],
161 $existingList = $this->restrictionsByBlockId(
162 $this->resultToRestrictions( $result )
168 foreach ( $restrictionList as $blockId => $blockRestrictions ) {
175 $restrictionsToRemove = $this->restrictionsToRemove(
176 $existingList[$blockId] ?? [],
180 if ( empty( $restrictionsToRemove ) ) {
184 $success = $this->
delete( $restrictionsToRemove );
190 $dbw->endAtomic( __METHOD__ );
205 if ( empty( $restrictions ) ) {
209 $parentBlockId = (int)$parentBlockId;
211 $db = $this->loadBalancer->getConnectionRef(
DB_PRIMARY, [], $this->wikiId );
213 $db->startAtomic( __METHOD__ );
215 $blockIds = $db->selectFieldValues(
218 [
'ipb_parent_block_id' => $parentBlockId ],
224 foreach ( $blockIds as $id ) {
230 $db->endAtomic( __METHOD__ );
243 public function delete( array $restrictions ) {
244 $dbw = $this->loadBalancer->getConnectionRef(
DB_PRIMARY, [], $this->wikiId );
246 foreach ( $restrictions as $restriction ) {
252 'ipblocks_restrictions',
255 $restriction->toRow(),
274 $dbw = $this->loadBalancer->getConnectionRef(
DB_PRIMARY, [], $this->wikiId );
276 'ipblocks_restrictions',
277 [
'ir_ipb_id' => $blockId ],
291 $dbw = $this->loadBalancer->getConnectionRef(
DB_PRIMARY, [], $this->wikiId );
292 return $dbw->deleteJoin(
293 'ipblocks_restrictions',
297 [
'ipb_parent_block_id' => $parentBlockId ],
312 public function equals( array $a, array $b ) {
313 $filter =
static function ( $restriction ) {
320 $a = array_filter( $a, $filter );
321 $b = array_filter( $b, $filter );
323 $aCount = count( $a );
324 $bCount = count( $b );
327 if ( $aCount !== $bCount ) {
332 if ( $aCount === 0 && $bCount === 0 ) {
336 $hasher =
static function ( $r ) {
337 return $r->getHash();
340 $aHashes = array_map( $hasher, $a );
341 $bHashes = array_map( $hasher, $b );
346 return $aHashes === $bHashes;
357 public function setBlockId( $blockId, array $restrictions ) {
358 $blockRestrictions = [];
360 foreach ( $restrictions as $restriction ) {
367 $restriction = clone $restriction;
368 $restriction->setBlockId( $blockId );
370 $blockRestrictions[] = $restriction;
373 return $blockRestrictions;
384 private function restrictionsToRemove( array $existing, array $new ) {
385 return array_filter( $existing,
static function ( $e ) use ( $new ) {
386 foreach ( $new as $restriction ) {
391 if ( $restriction->equals( $e ) ) {
407 private function restrictionsByBlockId( array $restrictions ) {
408 $blockRestrictions = [];
410 foreach ( $restrictions as $restriction ) {
412 if ( !$restriction instanceof Restriction ) {
416 if ( !isset( $blockRestrictions[$restriction->getBlockId()] ) ) {
417 $blockRestrictions[$restriction->getBlockId()] = [];
420 $blockRestrictions[$restriction->getBlockId()][] = $restriction;
423 return $blockRestrictions;
432 private function resultToRestrictions( IResultWrapper $result ) {
434 foreach ( $result as $row ) {
435 $restriction = $this->rowToRestriction( $row );
437 if ( !$restriction ) {
441 $restrictions[] = $restriction;
444 return $restrictions;
453 private function rowToRestriction( stdClass $row ) {
454 if ( array_key_exists( (
int)$row->ir_type, self::TYPES_MAP ) ) {
455 $class = self::TYPES_MAP[ (int)$row->ir_type ];
456 return call_user_func( [ $class,
'newFromRow' ], $row );