public function publish($isSynced = false)
    {
        // Logical checks prior to publish
        if ($this->State !== static::STATE_OPEN) {
            throw new BadMethodCallException(
                "ChangeSet can't be published if it has been already published or reverted."
            );
        }
        if (!$isSynced && !$this->isSynced()) {
            throw new ValidationException(
                "ChangeSet does not include all necessary changes and cannot be published."
            );
        }

        DB::get_conn()->withTransaction(function () {
            foreach ($this->Changes() as $change) {
                /** @var ChangeSetItem $change */
                $change->publish();
            }

            // Once this changeset is published, unlink any objects linking to
            // records in this changeset as unlinked (set RelationID to 0).
            // This is done as a safer alternative to deleting records on live that
            // are deleted on stage.
            foreach ($this->Changes() as $change) {
                /** @var ChangeSetItem $change */
                $change->unlinkDisownedObjects();
            }

            $this->State = static::STATE_PUBLISHED;
            $this->PublisherID = Security::getCurrentUser()
                ? Security::getCurrentUser()->ID
                : 0;
            $this->PublishDate = DBDatetime::now()->Rfc2822();

            $this->write();
        });
        return true;
    }