datatable.directory codebase
				https://datatable.directory/
			
			
		
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							697 lines
						
					
					
						
							18 KiB
						
					
					
				
			
		
		
	
	
							697 lines
						
					
					
						
							18 KiB
						
					
					
				| <?php
 | |
| 
 | |
| 
 | |
| namespace App\Tables;
 | |
| 
 | |
| use App\Models\Revision;
 | |
| use App\Models\Row;
 | |
| use App\Models\Table;
 | |
| use Illuminate\Pagination\Paginator;
 | |
| use Illuminate\Queue\SerializesModels;
 | |
| use Illuminate\Support\Collection;
 | |
| use MightyPork\Exceptions\NotApplicableException;
 | |
| use MightyPork\Exceptions\NotExistException;
 | |
| use ReflectionClass;
 | |
| 
 | |
| /**
 | |
|  * Object representing a set of table modifications
 | |
|  */
 | |
| class Changeset
 | |
| {
 | |
|     use SerializesModels;
 | |
| 
 | |
|     const object_excluded_properties = [
 | |
|         'revision',
 | |
|         'table',
 | |
|         'note',
 | |
|     ];
 | |
| 
 | |
|     /**
 | |
|      * @var Revision - base revision this changeset belongs to
 | |
|      */
 | |
|     public $revision;
 | |
| 
 | |
|     /**
 | |
|      * @var Table - table this changeset belongs to
 | |
|      */
 | |
|     public $table;
 | |
| 
 | |
|     /**
 | |
|      * @var string - user's note attached to this changeset (future proposal)
 | |
|      */
 | |
|     public $note = '';
 | |
| 
 | |
|     /**
 | |
|      * Rows whose content changed, identified by _id.
 | |
|      * Only changed values are to be filled. Columns are identified by GCIDs
 | |
|      *
 | |
|      * Key'd by _id
 | |
|      *
 | |
|      * @var array|null - [_id -> [_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 -> [_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 -> [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 = [];
 | |
| 
 | |
|     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 = $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 ($row instanceof Row) $row = (object)$row->getAttributes();
 | |
| 
 | |
|         if ($decorate) {
 | |
|             $row->_remove = false;
 | |
|             $row->_changed = [];
 | |
|             $row->_orig = [];
 | |
|         }
 | |
| 
 | |
|         if ($decorate) {
 | |
|             $row->_orig = array_diff((array)$row, []);
 | |
|             // remove junk
 | |
|             unset($row->_orig['_id']);
 | |
|             unset($row->_orig['_new']);
 | |
|             unset($row->_orig['_remove']);
 | |
|             unset($row->_orig['_changed']);
 | |
|             unset($row->_orig['_orig']);
 | |
|         }
 | |
| 
 | |
|         if ($this->isNewRow($row->_id)) {
 | |
|             if ($decorate) {
 | |
|                 $row->_new = true;
 | |
|             }
 | |
|             return $row;
 | |
|         }
 | |
| 
 | |
|         // Removed rows - return as null
 | |
|         if (in_array($row->_id, $this->removedRows)) {
 | |
|             if ($decorate) {
 | |
|                 $row->_remove = true;
 | |
|             } else {
 | |
|                 return null;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // if marked for removal, hide changes
 | |
|         if (!$row->_remove) {
 | |
|             // 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);
 | |
| 
 | |
|         if ($decorate) {
 | |
|             $row->_loadvals = array_diff((array)$row, []);
 | |
|             // remove junk
 | |
|             unset($row->_loadvals['_id']);
 | |
|             unset($row->_loadvals['_new']);
 | |
|             unset($row->_loadvals['_remove']);
 | |
|             unset($row->_loadvals['_changed']);
 | |
|             unset($row->_loadvals['_orig']);
 | |
|         }
 | |
| 
 | |
|         return $row;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Decorate / transform columns (loaded from the source revision)
 | |
|      *
 | |
|      * @return Column[]
 | |
|      */
 | |
|     public function fetchAndTransformColumns()
 | |
|     {
 | |
|         /** @var Column[] - loaded and transformed columns, cached from previous call to transformColumns() */
 | |
|         static $cachedColumns = [];
 | |
| 
 | |
|         if ($cachedColumns) return $cachedColumns;
 | |
|         $columns = Column::columnsFromJson($this->revision->columns);
 | |
| 
 | |
|         // Modify columns
 | |
|         foreach ($columns as $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
 | |
|         $colsById = collect($columns)->keyBy('id')->all();
 | |
|         $newOrder = [];
 | |
|         foreach ($this->columnOrder as $id) {
 | |
|             if (isset($colsById[$id])) {
 | |
|                 $newOrder[] = $colsById[$id];
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         $leftover_keys = array_diff(array_keys($colsById), $this->columnOrder);
 | |
|         foreach ($leftover_keys as $id) {
 | |
|             $newOrder[] = $colsById[$id];
 | |
|         }
 | |
| 
 | |
|         return $cachedColumns = $newOrder;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param string $id
 | |
|      * @return Column
 | |
|      */
 | |
|     public function fetchColumn(string $id)
 | |
|     {
 | |
|         if ($this->isNewColumn($id)) {
 | |
|             $c = new Column($this->newColumns[$id]);
 | |
|             $c->markAsNew();
 | |
|             return $c;
 | |
|         } else {
 | |
|             $columns = collect($this->revision->columns)->keyBy('id');
 | |
|             return new Column($columns[$id]);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param string $id
 | |
|      * @return Column
 | |
|      */
 | |
|     public function fetchAndTransformColumn(string $id)
 | |
|     {
 | |
|         $column = $this->fetchColumn($id);
 | |
| 
 | |
|         if (isset($this->columnUpdates[$column->id])) {
 | |
|             $column->modifyByChangeset($this->columnUpdates[$column->id]);
 | |
|         }
 | |
| 
 | |
|         if (in_array($column->id, $this->removedColumns)) {
 | |
|             $column->markForRemoval();
 | |
|         }
 | |
| 
 | |
|         return $column;
 | |
|     }
 | |
| 
 | |
|     public function rowRemove(int $id)
 | |
|     {
 | |
|         if ($this->isNewRow($id)) {
 | |
|             unset($this->newRows[$id]);
 | |
|         }
 | |
|         else {
 | |
|             $this->removedRows[] = $id;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     public function rowRestore(int $id)
 | |
|     {
 | |
|         $this->removedRows = array_diff($this->removedRows, [$id]);
 | |
|     }
 | |
| 
 | |
|     public function isNewRow(int $id)
 | |
|     {
 | |
|         return isset($this->newRows[$id]);
 | |
|     }
 | |
| 
 | |
|     public function isNewColumn(string $id)
 | |
|     {
 | |
|         return isset($this->newColumns[$id]);
 | |
|     }
 | |
| 
 | |
|     public function fetchAndTransformRow(int $id)
 | |
|     {
 | |
|         $r = $this->fetchRow($id);
 | |
|         $transformed = $this->transformRow($r, true);
 | |
|         return $transformed;
 | |
|     }
 | |
| 
 | |
|     public function fetchColumns()
 | |
|     {
 | |
|         return Column::columnsFromJson($this->revision->columns);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Fetch an existing row from DB, or a new row.
 | |
|      *
 | |
|      * @param $id
 | |
|      * @return object
 | |
|      */
 | |
|     public function fetchRow(int $id)
 | |
|     {
 | |
|         if ($this->isNewRow($id)) {
 | |
|             $nr = (object)$this->newRows[$id];
 | |
|             $nr->_new = true;
 | |
|             return $nr;
 | |
|         }
 | |
| 
 | |
|         $r = $this->revision->rowsData($this->fetchColumns(), true, false)
 | |
|             ->whereRaw("data->>'_id' = ?", $id)->first();
 | |
| 
 | |
|         if (!$r) throw new NotExistException("No such row _id = $id in this revision.");
 | |
| 
 | |
|         // remove junk
 | |
|         unset($r->pivot_revision_id);
 | |
|         unset($r->pivot_row_id);
 | |
| 
 | |
|         return (object)$r->getAttributes();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Apply a row update, adding the row to the list of changes, or removing it
 | |
|      * if all differences were undone.
 | |
|      *
 | |
|      * @param array|object $newVals - values of the new row
 | |
|      * @return object - updated column
 | |
|      */
 | |
|     public function rowUpdate($newVals)
 | |
|     {
 | |
|         $newVals = (object)$newVals;
 | |
| 
 | |
|         $_id = $newVals->_id;
 | |
|         $origRow = $this->fetchRow($_id);
 | |
| 
 | |
|         /** @var Column[]|Collection $cols */
 | |
|         $cols = collect($this->fetchAndTransformColumns())->keyBy('id');
 | |
| 
 | |
|         $updateObj = [];
 | |
| 
 | |
|         foreach ($newVals as $colId => $value) {
 | |
|             if (starts_with($colId, '_')) continue; // internals
 | |
| 
 | |
|             $col = $cols[$colId];
 | |
|             $value = $col->cast($value);
 | |
|             $origValue = $col->cast(isset($origRow->$colId) ? $origRow->$colId : null);
 | |
| 
 | |
|             if ($value !== $origValue) {
 | |
|                 $updateObj[$colId] = $value;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if ($this->isNewRow($_id)) {
 | |
|             $this->newRows[$_id] = array_merge($this->newRows[$_id], $updateObj);
 | |
|         }
 | |
|         else {
 | |
|             if (!empty($updateObj)) {
 | |
|                 $this->rowUpdates[$_id] = $updateObj;
 | |
|             } else {
 | |
|                 // remove possible old update record for this row, if nothing changes now
 | |
|                 unset($this->rowUpdates[$_id]);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return $this->fetchAndTransformRow($_id);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param $newVals
 | |
|      * @return Column
 | |
|      */
 | |
|     public function columnUpdate($newVals)
 | |
|     {
 | |
|         $id = $newVals->id;
 | |
|         $col = $this->fetchColumn($id);
 | |
| 
 | |
|         $updateObj = [];
 | |
|         foreach ($newVals as $field => $value) {
 | |
|             if (starts_with($field, '_')) continue; // internals
 | |
| 
 | |
|             if ($value !== $col->$field) {
 | |
|                 $updateObj[$field] = $value;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if ($this->isNewColumn($id)) {
 | |
|             $this->newColumns[$id] = array_merge($this->newColumns[$id], $updateObj);
 | |
|         }
 | |
|         else {
 | |
|             if (!empty($updateObj)) {
 | |
|                 $this->columnUpdates[$id] = $updateObj;
 | |
|             } else {
 | |
|                 // remove possible old update record for this row, if nothing changes now
 | |
|                 unset($this->columnUpdates[$id]);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return $this->fetchAndTransformColumn($id);
 | |
|     }
 | |
| 
 | |
|     public function columnRemove(string $id)
 | |
|     {
 | |
|         if ($this->isNewColumn($id)) {
 | |
|             unset($this->newColumns[$id]);
 | |
|             // remove it from order
 | |
|             $this->columnOrder = array_values(array_diff($this->columnOrder, [$id]));
 | |
|         }
 | |
|         else {
 | |
|             $this->removedColumns[] = $id;
 | |
|         }
 | |
| 
 | |
|         $this->clearColumnOrderIfUnchanged();
 | |
|     }
 | |
| 
 | |
|     public function columnRestore(string $id)
 | |
|     {
 | |
|         $this->removedColumns = array_diff($this->removedColumns, [$id]);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Get a page of added rows for display in the editor
 | |
|      *
 | |
|      * @param int $perPage
 | |
|      * @return \Illuminate\Pagination\LengthAwarePaginator|Collection|array
 | |
|      */
 | |
|     public function getAddedRows($perPage = 25)
 | |
|     {
 | |
|         return collection_paginate($this->newRows, $perPage);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param Column[] $columns
 | |
|      * @param array $csvArray
 | |
|      * @param bool $forTableInsert
 | |
|      * @return \array[][]|Collection
 | |
|      */
 | |
|     public static function csvToRowsArray($columns, $csvArray, $forTableInsert)
 | |
|     {
 | |
|         /** @var Collection|array[][] $rows */
 | |
|         $rows = collect($csvArray)->map(function ($row) use ($columns, $forTableInsert) {
 | |
|             if (count($row) == 0 || count($row) == 1 && $row[0] == '') return null; // discard empty lines
 | |
|             if (count($row) != count($columns)) {
 | |
|                 throw new NotApplicableException("All rows must have " . count($columns) . " fields.");
 | |
|             }
 | |
| 
 | |
|             $data = [];
 | |
| 
 | |
|             foreach ($row as $i => $val) {
 | |
|                 $col = $columns[$i];
 | |
| 
 | |
|                 if (strlen($val) > 1000) {
 | |
|                     // try to stop people inserting unstructured crap / malformed CSV
 | |
|                     throw new NotApplicableException("Value for column {$col->name} too long.");
 | |
|                 }
 | |
|                 $data[$col->id] = $col->cast($val);
 | |
|             }
 | |
| 
 | |
|             if ($forTableInsert) {
 | |
|                 return ['data' => $data];
 | |
|             } else {
 | |
|                 return $data;
 | |
|             }
 | |
|         })->filter();
 | |
| 
 | |
| 
 | |
|         $rowNumerator = new RowNumerator(count($csvArray));
 | |
| 
 | |
|         if ($forTableInsert) {
 | |
|             return $rows->map(function ($row) use (&$rowNumerator) {
 | |
|                 $row['data']['_id'] = $rowNumerator->next();
 | |
|                 return $row;
 | |
|             });
 | |
|         }
 | |
|         else {
 | |
|             return $rows->map(function ($row) use (&$rowNumerator) {
 | |
|                 $row['_id'] = $rowNumerator->next();
 | |
|                 return $row;
 | |
|             });
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     public function addBlankRows(int $count)
 | |
|     {
 | |
|         $numerator = new RowNumerator($count);
 | |
| 
 | |
|         $columns = $this->fetchAndTransformColumns();
 | |
|         $template = [];
 | |
|         foreach ($columns as $column) {
 | |
|             $template[$column->id] = $column->cast(null);
 | |
|         }
 | |
| 
 | |
|         foreach ($numerator->generate() as $_id) {
 | |
|             $row = $template;
 | |
|             $row['_id'] = $_id;
 | |
|             $this->newRows[$_id] = $row;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     public function addFilledRows($csvArray)
 | |
|     {
 | |
|         /** @var Column[] $columns */
 | |
|         $columns = array_values($this->fetchAndTransformColumns());
 | |
| 
 | |
|         $rows = self::csvToRowsArray($columns, $csvArray, false)
 | |
|             ->keyBy('_id');
 | |
| 
 | |
|         // using '+' to avoid renumbering
 | |
|         $this->newRows = $this->newRows + $rows->toArray();
 | |
|     }
 | |
| 
 | |
|     public function addBlankCol()
 | |
|     {
 | |
|         $cid = (new ColumnNumerator(1))->next();
 | |
| 
 | |
|         $allCols = $this->fetchAndTransformColumns();
 | |
|         $num = count($allCols) + 1;
 | |
| 
 | |
|         $col = [
 | |
|             'name' => "col_{$num}",
 | |
|             'type' => "string",
 | |
|             'title' => "Column {$num}",
 | |
|             'id' => $cid,
 | |
|             '_new' => true,
 | |
|         ];
 | |
| 
 | |
|         $this->newColumns[$cid] = $col;
 | |
|         return $col;
 | |
|     }
 | |
| 
 | |
|     public function setColOrder(array $order)
 | |
|     {
 | |
|         $allCols = $this->fetchAndTransformColumns();
 | |
|         $ids = collect($allCols)->pluck('id')->all();
 | |
|         $order = array_intersect($order, $ids);
 | |
|         $missing = array_diff($ids, $order);
 | |
| 
 | |
|         $this->columnOrder = array_values(array_merge($order, $missing));
 | |
|         $this->clearColumnOrderIfUnchanged();
 | |
|     }
 | |
| 
 | |
|     public function removeEmptyNewRows()
 | |
|     {
 | |
|         $cols = $this->fetchColumns();
 | |
|         $emptyTpl = collect($cols)->keyBy('id')->map(function(Column $c) {
 | |
|             return $c->cast(null);
 | |
|         })->all();
 | |
| 
 | |
|         foreach ($this->newColumns as $k => $obj) {
 | |
|             $cols[] = $c = new Column($obj);
 | |
|             $c->markAsNew();
 | |
| 
 | |
|             $emptyTpl[$k] = $c->cast(null);
 | |
|         }
 | |
| 
 | |
|         $this->newRows = array_filter($this->newRows, function ($r) use ($emptyTpl) {
 | |
|             foreach ($r as $k => $val) {
 | |
|                 if ($k[0] == '_') continue;
 | |
|                 if ($val != $emptyTpl[$k]) return true;
 | |
|             }
 | |
|             return false;
 | |
|         });
 | |
|     }
 | |
| 
 | |
|     public function clearColumnOrderIfUnchanged()
 | |
|     {
 | |
|         $expected = collect($this->revision->columns)
 | |
|             ->pluck('id')
 | |
|             ->diff($this->removedColumns)
 | |
|             ->merge(collect($this->newColumns)->pluck('id'))
 | |
|             ->values()->all();
 | |
| 
 | |
|         $this->columnOrder = array_values($this->columnOrder);
 | |
| 
 | |
|         if ($expected == $this->columnOrder) {
 | |
|             $this->columnOrder = [];
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     public function resetColumnOrder()
 | |
|     {
 | |
|         $this->columnOrder = [];
 | |
|     }
 | |
| 
 | |
|     public function resetRemovedColumns()
 | |
|     {
 | |
|         $this->removedColumns = [];
 | |
|     }
 | |
| 
 | |
|     public function resetAddedColumns()
 | |
|     {
 | |
|         $this->columnOrder = array_values(
 | |
|             array_diff($this->columnOrder,
 | |
|                 collect($this->newColumns)->pluck('id')->all()
 | |
|             )
 | |
|         );
 | |
| 
 | |
|         $this->newColumns = [];
 | |
|         $this->clearColumnOrderIfUnchanged();
 | |
|     }
 | |
| 
 | |
|     public function resetUpdatedColumns()
 | |
|     {
 | |
|         $this->columnUpdates = [];
 | |
|     }
 | |
| 
 | |
|     public function resetRemovedRows()
 | |
|     {
 | |
|         $this->removedRows = [];
 | |
|     }
 | |
| 
 | |
|     public function resetAddedRows()
 | |
|     {
 | |
|         $this->newRows = [];
 | |
|     }
 | |
| 
 | |
|     public function resetUpdatedRows()
 | |
|     {
 | |
|         $this->rowUpdates = [];
 | |
|     }
 | |
| }
 | |
| 
 |