$journal */ public function __construct( public readonly FixState $state, public readonly int $links_done, public readonly int $places_total, public readonly int $places_done, public readonly int $places_failed, public readonly array $journal ) { } public function with_state( FixState $state ): self { return new self( $state, $this->links_done, $this->places_total, $this->places_done, $this->places_failed, $this->journal ); } public function with_links_done( int $links_done ): self { return new self( $this->state, max( 0, $links_done ), $this->places_total, $this->places_done, $this->places_failed, $this->journal ); } public function with_place( JournalEntry $entry ): self { $is_changed = null !== $entry->content_before_fix; $places_done = $this->places_done + ( $is_changed ? 1 : 0 ); $places_failed = $this->places_failed + ( $is_changed ? 0 : 1 ); return new self( $this->state, $this->links_done, max( $this->places_total, $places_done + $places_failed ), $places_done, $places_failed, array( ...$this->journal, $entry ) ); } public function without_last_place(): self { $journal = $this->journal; $entry = array_pop( $journal ); $is_changed = null !== $entry?->content_before_fix; return new self( $this->state, $this->links_done, $this->places_total, max( 0, $this->places_done - ( $is_changed ? 1 : 0 ) ), max( 0, $this->places_failed - ( $is_changed ? 0 : 1 ) ), $journal ); } public function has_unchanged_place_of( int $link_id ): bool { foreach ( $this->journal as $entry ) { if ( $link_id === $entry->link_id && null === $entry->content_before_fix ) { return true; } } return false; } public function places_handled(): int { return $this->places_done + $this->places_failed; } /** @return list */ public function posts_journaled_for( int $link_id ): array { $post_ids = array(); foreach ( $this->journal as $entry ) { if ( $link_id === $entry->link_id ) { $post_ids[] = $entry->post_id; } } return $post_ids; } }