diff --git a/app/Http/Controllers/TableEditController.php b/app/Http/Controllers/TableEditController.php index f4dbc79..6a09a6d 100644 --- a/app/Http/Controllers/TableEditController.php +++ b/app/Http/Controllers/TableEditController.php @@ -11,6 +11,9 @@ use Illuminate\Support\Facades\Input; use MightyPork\Exceptions\SimpleValidationException; use MightyPork\Utils\Utils; +/** + * Draft composing + */ class TableEditController extends Controller { /** diff --git a/app/Tables/Changeset.php b/app/Tables/Changeset.php index e9fb694..d68dedd 100644 --- a/app/Tables/Changeset.php +++ b/app/Tables/Changeset.php @@ -6,7 +6,6 @@ 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; @@ -105,6 +104,12 @@ class Changeset */ public $removedColumns = []; + /** + * Generator iterating all properties, used internally for serialization to array + * + * @return \Generator + * @throws \ReflectionException + */ private function walkProps() { $properties = (new ReflectionClass($this))->getProperties(); @@ -299,6 +304,8 @@ class Changeset } /** + * Retrieve a column by ID (even new columns) + * * @param string $id * @return Column */ @@ -315,7 +322,9 @@ class Changeset } /** - * @param string $id + * Retrieve a column and modify it by the Changeset. + * + * @param string $id - column ID * @return Column */ public function fetchAndTransformColumn(string $id) @@ -333,6 +342,11 @@ class Changeset return $column; } + /** + * Mark a row for removal + * + * @param int $id - row ID (_id) + */ public function rowRemove(int $id) { if ($this->isNewRow($id)) { @@ -343,21 +357,44 @@ class Changeset } } + /** + * Undo row removal + * + * @param int $id - row ID (_id) + */ public function rowRestore(int $id) { $this->removedRows = array_diff($this->removedRows, [$id]); } + /** + * Test if a row is new + * + * @param int $id - row ID (_id) + * @return bool - is new + */ public function isNewRow(int $id) { return isset($this->newRows[$id]); } + /** + * Test if a column is new + * + * @param string $id - column ID + * @return bool - is new + */ public function isNewColumn(string $id) { return isset($this->newColumns[$id]); } + /** + * Retrieve a single row and transform it by the Changeset + * + * @param int $id - row ID (_id) + * @return \DecoratedRow|object + */ public function fetchAndTransformRow(int $id) { $r = $this->fetchRow($id); @@ -365,7 +402,12 @@ class Changeset return $transformed; } - public function fetchColumns() + /** + * Fetch columns from DB (not including new columns) + * + * @return Column[] + */ + public function fetchRevisionColumns() { return Column::columnsFromJson($this->revision->columns); } @@ -384,7 +426,7 @@ class Changeset return $nr; } - $r = $this->revision->rowsData($this->fetchColumns(), true, false) + $r = $this->revision->rowsData($this->fetchRevisionColumns(), true, false) ->whereRaw("data->>'_id' = ?", $id)->first(); if (!$r) throw new NotExistException("No such row _id = $id in this revision."); @@ -443,8 +485,10 @@ class Changeset } /** - * @param $newVals - * @return Column + * Update a column specification + * + * @param object $newVals - new values for the column + * @return Column - the column, modified and decorated with _orig etc */ public function columnUpdate($newVals) { @@ -475,6 +519,11 @@ class Changeset return $this->fetchAndTransformColumn($id); } + /** + * Mark a column for removal, or forget it if it's a new column + * + * @param string $id - column ID + */ public function columnRemove(string $id) { if ($this->isNewColumn($id)) { @@ -489,13 +538,18 @@ class Changeset $this->clearColumnOrderIfUnchanged(); } + /** + * Restore a column previously marked for removal + * + * @param string $id - column ID + */ public function columnRestore(string $id) { $this->removedColumns = array_diff($this->removedColumns, [$id]); } /** - * Get a page of added rows for display in the editor + * Get a page of new rows, for display in the editor * * @param int $perPage * @return \Illuminate\Pagination\LengthAwarePaginator|Collection|array @@ -506,14 +560,18 @@ class Changeset } /** - * @param Column[] $columns - * @param array $csvArray - * @param bool $forTableInsert - * @return \array[][]|Collection + * Convert a raw CSV array to a rows array, validating and casting the data. + * All created rows are assigned globally unique IDs + * + * @param Column[] $columns - ordered array of columns to collect from all CSV rows + * @param array $csvArray - CSV parsed to 2D array + * @param bool $forTableInsert - if true, row data will be wrapped in ['data'=>...] + * so it can be inserted directly into DB + * @return Collection */ public static function csvToRowsArray($columns, $csvArray, $forTableInsert) { - /** @var Collection|array[][] $rows */ + /** @var Collection $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)) { @@ -539,7 +597,8 @@ class Changeset } })->filter(); - + // TODO we could use some temporary IDs and replace them with + // TODO proper unique IDs when submitting the proposal $rowNumerator = new RowNumerator(count($csvArray)); if ($forTableInsert) { @@ -556,16 +615,23 @@ class Changeset } } + /** + * Append N blank rows + * + * @param int $count + */ public function addBlankRows(int $count) { - $numerator = new RowNumerator($count); - $columns = $this->fetchAndTransformColumns(); $template = []; foreach ($columns as $column) { $template[$column->id] = $column->cast(null); } + // TODO we could use some temporary IDs and replace them with + // TODO proper unique IDs when submitting the proposal + $numerator = new RowNumerator($count); + foreach ($numerator->generate() as $_id) { $row = $template; $row['_id'] = $_id; @@ -573,6 +639,11 @@ class Changeset } } + /** + * Add rows from imported CSV + * + * @param array $csvArray - CSV parsed to 2D array + */ public function addFilledRows($csvArray) { /** @var Column[] $columns */ @@ -585,6 +656,11 @@ class Changeset $this->newRows = $this->newRows + $rows->toArray(); } + /** + * Add a blank column (pre-filled with dummies to satisfy validation) + * + * @return array - column array + */ public function addBlankCol() { $cid = (new ColumnNumerator(1))->next(); @@ -604,6 +680,11 @@ class Changeset return $col; } + /** + * Set a new column order + * + * @param array $order - array of column IDs + */ public function setColOrder(array $order) { $allCols = $this->fetchAndTransformColumns(); @@ -615,9 +696,12 @@ class Changeset $this->clearColumnOrderIfUnchanged(); } + /** + * Remove added rows that are not filled (user added too many with the Add Rows form) + */ public function removeEmptyNewRows() { - $cols = $this->fetchColumns(); + $cols = $this->fetchRevisionColumns(); $emptyTpl = collect($cols)->keyBy('id')->map(function(Column $c) { return $c->cast(null); })->all(); @@ -638,6 +722,10 @@ class Changeset }); } + /** + * Discard the column order array if it's identical to the natural / default + * ordering. This simplifies the Changeset and reduces possible conflicts + */ public function clearColumnOrderIfUnchanged() { $expected = collect($this->revision->columns) @@ -653,16 +741,25 @@ class Changeset } } + /** + * Clear the custom column order + */ public function resetColumnOrder() { $this->columnOrder = []; } + /** + * Restore all columns marked for removal + */ public function resetRemovedColumns() { $this->removedColumns = []; } + /** + * Discard all added columns + */ public function resetAddedColumns() { $this->columnOrder = array_values( @@ -675,21 +772,33 @@ class Changeset $this->clearColumnOrderIfUnchanged(); } + /** + * Discard all column changes + */ public function resetUpdatedColumns() { $this->columnUpdates = []; } + /** + * Restore all rows marked for removal + */ public function resetRemovedRows() { $this->removedRows = []; } + /** + * Discard all added rows + */ public function resetAddedRows() { $this->newRows = []; } + /** + * Discard all row changes + */ public function resetUpdatedRows() { $this->rowUpdates = [];