Index

BoardSync

MMO\git\helpers · 1 symbol · generated 5 Oct 2026

class

BoardSync

BoardSync.php:41

Merge two repositories of mmo.client's kanban entities (KanbanBoard, KanbanTicket, KanbanComment) into each other, when asked: a local one -- a JsonRepository, mmo.mongodb's MongoRepository -- where the tickets are worked on, and a remote one, usually a GitHubRepository (a GitHub project, or a repository's issues). Each side keeps its own ids; a sync writes on each side what the other changed since the last one.

class MMO\git\helpers\BoardSync
Namespace
MMO\git\helpers
See
$match (the same title, by default) before any is made. - A ticket removed on one side is removed on the other, unless the other changed it since (a conflict), or, $deletions is false. - The statuses are paired by $statuses, else by their label, else by their id, else by their type; the categories and the labels by their label. A parent, or a ticket a constraint names, is the paired ticket. - The comments are merged the same way, ticket by ticket, when the remote ticket has a discussion (a project's draft has none: its comments stay local). A comment made on GitHub says who wrote it locally when it is not the token's owner; only the token's owner's comments are changed or removed there. - What one side cannot keep (a draft's labels) is not a change: the remote side is read again after it is written, and what it kept is what the next sync compares with.
### How it merges It is a three-way merge: [`$state`](https://mcp.mmoframework.fr/documentation/mmo.git/php/helpers/BoardSync.md#boardsync-state) keeps, for each pair of tickets (a local id, a remote id), what both sides held at the end of the last sync, field by field. A field changed on one side only is written on the other; changed on both to different values, it is a conflict, settled by [`$conflicts`](https://mcp.mmoframework.fr/documentation/mmo.git/php/helpers/BoardSync.md#boardsync-conflicts) (left as it is on both sides by default, and reported until one side is changed to match the other). - A ticket on one side only is made on the other. The first time, the tickets of both sides are paired by Nothing is written on a dry run: the report says what would be.
$local = new JsonRepository(['boards' => 'data/boards.json', 'tickets' => 'data/tickets.json', 'comments' => 'data/comments.json'], COLLECTIONS); $github = new GitHubRepository(COLLECTIONS, project: 'https://github.com/orgs/oviepro/projects/28'); $report = (new BoardSync($local, $github, 'data/main.sync.json'))->run(dryRun: true); // ['local' => ['created' => [...], 'updated' => [...], 'removed' => [...]], 'remote' => [...], 'conflicts' => [...], ...]

Index

DEFAULT_STATUSESa board without statuses has <mmo-kanban>'s
FIELDSa ticket's fields that are merged: the kanban's names
LOCALthe side a conflict is settled for, or neither
REFERENCESthe fields naming other tickets: written once the tickets they name are on both sides
REMOTE
SKIP
conflicts
deletions
local
localBoard
maps
match
matchId
remote
remoteBoard
report
state
stateFile
statuses
attribute($comment, $viewer)
board($side)
boards($dryRun)a side without the board gets it, with the other's settings
buildMaps()
collection($side, $class)
comments($side, $ticket)
data($ticket)
discusses($remoteTicket)
discussions()merge the comments of each pair of tickets whose remote one has a discussion
explicitRemoteIds($remoteStatuses)
merge($created, $dryRun)Merge the fields of each pair: what changed on one side since the last sync is written on the other.
mergeComments($l, $r, $local, $remote, $viewer)
name($side)
other($side)
pairAndCreate($dryRun)Pair the tickets, make on each side those it lacks, and remove those removed on the other.
pairList($from, $to, $explicit, $byType)
readState()
reload()read the remote side again: what it kept of what was written, and the ids it gave
removeTicket($side, $ticket)remove a ticket and the comments its side holds already
run($dryRun)Merge the two boards into each other.
sideReport()
tickets($side)
translate($data, $from, $only)
translateCondition($node, $pairs)
translateLabels($labels, $from)
unpair($local)
writeState()write through a temporary file: a crash never leaves half a state
__construct($local, $remote, $stateFile, $localBoard, $remoteBoard)

Constants6

DEFAULT_STATUSES

a board without statuses has <mmo-kanban>'s

const DEFAULT_STATUSES = […5 items]

FIELDS

a ticket's fields that are merged: the kanban's names

const FIELDS = […10 items]

LOCAL

the side a conflict is settled for, or neither

const LOCAL = 'local'

REFERENCES

the fields naming other tickets: written once the tickets they name are on both sides

const REFERENCES = ['parent', 'constraint']

REMOTE

const REMOTE = 'remote'

SKIP

const SKIP = 'skip'

Properties13

conflicts

string $conflicts = 'skip'
Type
string

deletions

bool $deletions = true
Type
bool

local

protected MMO\core\classes\aRepository $local
Type
aRepository

localBoard

protected string $localBoard
Type
string

maps

protected array $maps = []
Type
array

remote

protected MMO\core\classes\aRepository $remote
Type
aRepository

remoteBoard

protected string $remoteBoard
Type
string

report

protected array $report = []
Type
array

state

protected array $state = ['pairs' => [], 'base' => [], 'comments' => []]
Type
array

stateFile

protected string $stateFile
Type
string

statuses

array $statuses = []
Type
array

Methods28

attribute($comment, $viewer)

BoardSync.php:556
protected function attribute(MMO\client\entities\KanbanComment $comment, ?string $viewer): string
$commentKanbanComment
$viewernull | string
returnsstringa local comment's body as it is written on the remote side: saying who wrote it, when it is not who writes there

boards($dryRun)

BoardSync.php:132

a side without the board gets it, with the other's settings

protected function boards(bool $dryRun): void
$dryRunbool
returnsvoid

buildMaps()

BoardSync.php:153
protected function buildMaps(): array
returnsarrayarray<string, ?string>> the statuses and categories of each side, by the other's ids

collection($side, $class)

BoardSync.php:587
protected function collection(string $side, string $class): MMO\core\interfaces\iCollection
$sidestring
$classstring
returnsiCollectionthe side's collection of $class
throwswhen it has none

comments($side, $ticket)

BoardSync.php:571
protected function comments(string $side, string $ticket): array
$sidestring
$ticketstring
returnsarrayKanbanComment> a ticket's comments on a side, by id, oldest first

data($ticket)

BoardSync.php:417
protected function data(MMO\client\entities\KanbanTicket $ticket): array
$ticketKanbanTicket
returnsarraythe merged fields of a ticket, as the kanban names them, the labels in order

discusses($remoteTicket)

BoardSync.php:565
protected function discusses(string $remoteTicket): bool
$remoteTicketstring
returnsboolwhether the remote ticket has a discussion: a GitHub project's draft has none

discussions()

BoardSync.php:452

merge the comments of each pair of tickets whose remote one has a discussion

protected function discussions(): void
returnsvoid

explicitRemoteIds($remoteStatuses)

BoardSync.php:171
protected function explicitRemoteIds(array $remoteStatuses): array
$remoteStatusesarray
returnsarraystring> $statuses, its remote statuses given by their id

merge($created, $dryRun)

BoardSync.php:298

Merge the fields of each pair: what changed on one side since the last sync is written on the other.

protected function merge(array $created, bool $dryRun): void
$createdarray
$dryRunbool
returnsvoid

mergeComments($l, $r, $local, $remote, $viewer)

BoardSync.php:473
protected function mergeComments(string $l, string $r, array $local, array $remote, ?string $viewer): void
$lstring
$rstring
$localarray
$remotearray
$viewernull | stringwho writes on the remote side: the only one whose comments can be changed there
returnsvoid

pairAndCreate($dryRun)

BoardSync.php:214

Pair the tickets, make on each side those it lacks, and remove those removed on the other.

protected function pairAndCreate(bool $dryRun): array
$dryRunbool
returnsarraystring> the pairs made this run, by local id => the side the ticket came from

pairList($from, $to, $explicit, $byType)

BoardSync.php:188
protected function pairList(array $from, array $to, array $explicit = [], bool $byType = true): array
$fromarraya list of statuses or categories
$toarray
$explicit = []array
$byType = trueboolwhether an item without a match takes the first of $to of its type
returnsarray?string> each id of $from => the id of $to it is, null for none

readState()

BoardSync.php:611
protected function readState(): array
returnsarrayarray<string, string>, base: array<string, array>, comments: array<string, array>}

reload()

BoardSync.php:601

read the remote side again: what it kept of what was written, and the ids it gave

protected function reload(): void
returnsvoid

removeTicket($side, $ticket)

BoardSync.php:437

remove a ticket and the comments its side holds already

protected function removeTicket(string $side, MMO\client\entities\KanbanTicket $ticket): void
$sidestring
$ticketKanbanTicket
returnsvoid

run($dryRun)

BoardSync.php:112

Merge the two boards into each other.

function run(bool $dryRun = false): array
$dryRun = falseboolonly say what would be done
returnsarray{dryRun, local, remote, conflicts, notes}: what was done on each side (created, updated, removed tickets, comments), the conflicts left, and what could not be synced
throwswhen a side refuses a change: what was done before is kept in the state

sideReport()

BoardSync.php:606
protected function sideReport(): array
returnsarraylist<array>, updated: list<array>, removed: list<array>, comments: array{created: int, updated: int, removed: int}}

tickets($side)

BoardSync.php:428
protected function tickets(string $side): array
$sidestring
returnsarrayKanbanTicket> the side's tickets of its board, by id

translate($data, $from, $only)

BoardSync.php:377
protected function translate(array $data, string $from, bool $only = true): array
$dataarrayfields of a ticket of the $from side
$fromstring
$only = trueboolwhether to translate the fields given only (a field missing stays missing)
returnsarraythem as the other side names them: its statuses, categories, labels and tickets

translateCondition($node, $pairs)

BoardSync.php:407
protected function translateCondition(mixed $node, array $pairs): mixed
$nodemixed
$pairsarray
returnsmixedthe condition, the tickets it names the other side's (one never synced is left as it is)

translateLabels($labels, $from)

BoardSync.php:394
protected function translateLabels(array $labels, string $from): array
$labelsarray
$fromstring
returnsarraythe labels as the other side names them: by their label, else as they are called

writeState()

BoardSync.php:622

write through a temporary file: a crash never leaves half a state

protected function writeState(): void
returnsvoid

__construct($local, $remote, $stateFile, $localBoard, $remoteBoard)

BoardSync.php:101
function __construct( MMO\core\classes\aRepository $local, MMO\core\classes\aRepository $remote, string $stateFile, string $localBoard = 'main', ?string $remoteBoard = null )
$localaRepositorythe repository the tickets are worked on in
$remoteaRepositorythe one it is synced with: a GitHubRepository, or any repository of kanban entities
$stateFilestringa JSON file keeping what both sides held at the end of the last sync ({root} and the like are expanded): the pairs of tickets and comments, and their fields. Lost, the next sync pairs the tickets by $match again, and settles every difference as a conflict.
$localBoard = 'main'stringthe name of the local board
$remoteBoard = nullnull | stringthe name of the remote one; null: a GitHubRepository's board, else $localBoard