[_id:…, cid:…, cid:…], …] */ public $rowUpdates = []; /** * New rows in the full Row::data format, including GRIDs. * Values are identified by GCIDs from previously defined, or new columns. * * @var array|null - [[_id:…, cid:…, cid:…], …] */ public $newRows = []; /** * Rows to be removed * * @var int[]|null - GRIDs */ public $removedRows = []; /** * Values changed in column specifications, such as name, title, etc. * This does not affect the table rows in any way. * * Key'd by id * * @var array[] - column specification objects, with GCIDs, key'd by CID */ public $columnUpdates = []; /** * New columns in the full format, including GCIDs * * @var array|null - [[id:…, …], …] */ public $newColumns = []; /** * When reordering columns, here is the column IDs array * in the new order. Columns meanwhile removed from the table * or added to it are to be ignored or appended at the end. * * This shall not be filled if merely editing or adding columns, * unless the order is explicitly adjusted by the user. * * @var string[]|null - GCIDs */ public $columnOrder = []; /** * Columns to be removed * * The data associated to those columns may or may not be removed from the Rows. * It does not matter, other than in regard to the table size. * * @var int[]|null - GCIDs */ public $removedColumns = []; /** @var Column[] - loaded and transformed columns, cached from previous call to transformColumns() */ private $cachedColumns; private function walkProps() { $properties = (new ReflectionClass($this))->getProperties(); foreach ($properties as $property) { if (in_array($property->name, self::object_excluded_properties)) { continue; } yield $property->name; } } /** * Reconstruct from a object, such as one found in Proposal. * Note that the fromProposal() method should be used when the * proposal is available, as it populates additional fields. * * @param \stdClass $changes * @return Changeset */ public static function fromObject($changes) { $changeset = new Changeset(); foreach ($changeset->walkProps() as $prop) { if (isset($changes->$prop)) { $changeset->$prop = $changes->$prop; } } return $changeset; } /** * Serialize to an object format that may be stored in a Proposal. * * @return \stdClass */ public function toObject() { $object = new \stdClass(); foreach ($this->walkProps() as $prop) { $object->$prop = array_values($this->$prop); } return $object; } /** * Check if there is any change in this changeset * * @return bool - any found */ public function hasAnyChanges() { foreach ($this->walkProps() as $prop) { if (!empty($this->$prop)) { return true; } } return false; } /** * Decorate / transform a single row for the editor view * * @param object|\DecoratedRow $row - row, must be key'd by column ids * @param bool $decorate - to add extra underscored info for the editor * @return \DecoratedRow|object|null - null if not decorating and the row was removed */ public function transformRow($row, $decorate) { if ($decorate) { $row->_remove = false; $row->_changed = []; $row->_orig = []; } // Removed rows if (in_array($row->_id, $this->removedRows)) { if ($decorate) { $row->_remove = true; } else { return null; } } // Changed values if (isset($this->rowUpdates[$row->_id])) { $newVals = $this->rowUpdates[$row->_id]; if ($decorate) { $row->_changed = array_keys($newVals); $row->_orig = array_only((array)$row, $row->_changed); } $row = (object)array_merge((array)$row, $newVals); } // Drop deleted columns if (!$decorate) { foreach ($this->removedColumns as $colId) { unset($row->$colId); } } unset($row->_row_pivot); return $row; } /** * Decorate / transform columns (loaded from the source revision) * * @return Column[] */ public function transformColumns() { if ($this->cachedColumns) return $this->cachedColumns; $columns = Column::columnsFromJson($this->revision->columns); // Modify columns $byId = []; foreach ($columns as $column) { $byId[$column->id] = $column; if (isset($this->columnUpdates[$column->id])) { $column->modifyByChangeset($this->columnUpdates[$column->id]); } if (in_array($column->id, $this->removedColumns)) { $column->markForRemoval(); } } // Append new columns foreach ($this->newColumns as $newColumn) { $columns[] = $c =new Column($newColumn); $c->markAsNew(); } // Reorder $newOrder = []; foreach ($this->columnOrder as $id) { $newOrder[] = $byId[$id]; } $leftover_keys = array_diff(array_keys($byId), $this->columnOrder); foreach ($leftover_keys as $id) { $newOrder[] = $byId[$id]; } return $this->cachedColumns = $newOrder; } }