X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FStorage%2FSlotRecord.php;h=dff4b031d40c63ca5259132f6351aabdabb289cc;hb=06817f758c18cf90e4d67e12a7373bde20a65e91;hp=50d11005476b7c7be9013973791435035f3af4cd;hpb=a7e2b91b2c72f3522a7a9c3c957a43309e70b92e;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/Storage/SlotRecord.php b/includes/Storage/SlotRecord.php index 50d1100547..dff4b031d4 100644 --- a/includes/Storage/SlotRecord.php +++ b/includes/Storage/SlotRecord.php @@ -38,7 +38,9 @@ use Wikimedia\Assert\Assert; class SlotRecord { /** - * @var object database result row, as a raw object + * @var object database result row, as a raw object. Callbacks are supported for field values, + * to enable on-demand emulation of these values. This is primarily intended for use + * during schema migration. */ private $row; @@ -142,11 +144,11 @@ class SlotRecord { /** * Constructs a complete SlotRecord for a newly saved revision, based on the incomplete * proto-slot. This adds information that has only become available during saving, - * particularly the revision ID and content address. + * particularly the revision ID, content ID and content address. * * @param int $revisionId the revision the slot is to be associated with (field slot_revision_id). * If $protoSlot already has a revision, it must be the same. - * @param int $contentId the ID of the row in the content table describing the content + * @param int|null $contentId the ID of the row in the content table describing the content * referenced by $contentAddress (field slot_content_id). * If $protoSlot already has a content ID, it must be the same. * @param string $contentAddress the slot's content address (field content_address). @@ -163,7 +165,8 @@ class SlotRecord { SlotRecord $protoSlot ) { Assert::parameterType( 'integer', $revisionId, '$revisionId' ); - Assert::parameterType( 'integer', $contentId, '$contentId' ); + // TODO once migration is over $contentId must be an integer + Assert::parameterType( 'integer|null', $contentId, '$contentId' ); Assert::parameterType( 'string', $contentAddress, '$contentAddress' ); if ( $protoSlot->hasRevision() && $protoSlot->getRevision() !== $revisionId ) { @@ -181,7 +184,7 @@ class SlotRecord { ); } - if ( $protoSlot->hasAddress() && $protoSlot->getContentId() !== $contentId ) { + if ( $protoSlot->hasContentId() && $protoSlot->getContentId() !== $contentId ) { throw new LogicException( "Mismatching content ID $contentId: " . "The slot already has content row {$protoSlot->getContentId()} associated." @@ -231,11 +234,6 @@ class SlotRecord { Assert::parameterType( 'object', $row, '$row' ); Assert::parameterType( 'Content|callable', $content, '$content' ); - Assert::parameter( - property_exists( $row, 'slot_id' ), - '$row->slot_id', - 'must exist' - ); Assert::parameter( property_exists( $row, 'slot_revision_id' ), '$row->slot_revision_id', @@ -379,6 +377,13 @@ class SlotRecord { * @return bool whether this record contains the given field */ private function hasField( $name ) { + if ( isset( $this->row->$name ) ) { + // if the field is a callback, resolve first, then re-check + if ( !is_string( $this->row->$name ) && is_callable( $this->row->$name ) ) { + $this->getField( $name ); + } + } + return isset( $this->row->$name ); } @@ -430,6 +435,30 @@ class SlotRecord { return $this->hasField( 'content_address' ); } + /** + * Whether this slot has an origin (revision ID that originated the slot's content. + * + * @since 1.32 + * + * @return bool + */ + public function hasOrigin() { + return $this->hasField( 'slot_origin' ); + } + + /** + * Whether this slot has a content ID. Slots will have a content ID if their + * content has been stored in the content table. While building a new revision, + * SlotRecords will not have an ID associated. + * + * @since 1.32 + * + * @return bool + */ + public function hasContentId() { + return $this->hasField( 'slot_content_id' ); + } + /** * Whether this slot has revision ID associated. Slots will have a revision ID associated * only if they were loaded as part of an existing revision. While building a new revision, @@ -565,4 +594,50 @@ class SlotRecord { return \Wikimedia\base_convert( sha1( $blob ), 16, 36, 31 ); } + /** + * Returns true if $other has the same content as this slot. + * The check is performed based on the model, address size, and hash. + * Two slots can have the same content if they use different content addresses, + * but if they have the same address and the same model, they have the same content. + * Two slots can have the same content if they belong to different + * revisions or pages. + * + * Note that hasSameContent() may return false even if Content::equals returns true for + * the content of two slots. This may happen if the two slots have different serializations + * representing equivalent Content. Such false negatives are considered acceptable. Code + * that has to be absolutely sure the Content is really not the same if hasSameContent() + * returns false should call getContent() and compare the Content objects directly. + * + * @since 1.32 + * + * @param SlotRecord $other + * @return bool + */ + public function hasSameContent( SlotRecord $other ) { + if ( $other === $this ) { + return true; + } + + if ( $this->getModel() !== $other->getModel() ) { + return false; + } + + if ( $this->hasAddress() + && $other->hasAddress() + && $this->getAddress() == $other->getAddress() + ) { + return true; + } + + if ( $this->getSize() !== $other->getSize() ) { + return false; + } + + if ( $this->getSha1() !== $other->getSha1() ) { + return false; + } + + return true; + } + }