60 changed files with 2067 additions and 428 deletions
@ -0,0 +1,12 @@
|
||||
.PHONY: build dev watch prod ana |
||||
|
||||
build: dev |
||||
|
||||
dev: |
||||
npm run dev
|
||||
watch: |
||||
npm run watch
|
||||
ana: |
||||
npm run dev-analyze
|
||||
prod: |
||||
npm run prod
|
@ -0,0 +1,18 @@
|
||||
<?php |
||||
|
||||
/** |
||||
* Interface RowData |
||||
* |
||||
* @property int $_id |
||||
*/ |
||||
interface RowData {} |
||||
|
||||
/** |
||||
* Interface DecoratedRow |
||||
* |
||||
* @property bool $_new - row is new in the changeset |
||||
* @property bool $_remove - marked to be removed |
||||
* @property mixed[] $_orig - original values before transformation, key by CID |
||||
* @property string[] $_changed - values that were changed |
||||
*/ |
||||
interface DecoratedRow extends RowData {} |
@ -1,14 +0,0 @@
|
||||
<?php |
||||
|
||||
namespace FlowBox\Exceptions; |
||||
|
||||
class ViewException extends FBRuntimeException |
||||
{ |
||||
public $captured; |
||||
|
||||
public function __construct(\Exception $cause, $captured) |
||||
{ |
||||
$this->captured = $captured; |
||||
parent::__construct($cause); |
||||
} |
||||
} |
@ -0,0 +1,174 @@
|
||||
<?php |
||||
|
||||
|
||||
namespace App\Http\Controllers; |
||||
|
||||
use App\Models\Table; |
||||
use App\Models\User; |
||||
use App\Tables\Changeset; |
||||
use Illuminate\Http\Request; |
||||
use Illuminate\Support\Facades\Input; |
||||
use MightyPork\Exceptions\SimpleValidationException; |
||||
use MightyPork\Utils\Utils; |
||||
|
||||
class TableEditController extends Controller |
||||
{ |
||||
/** |
||||
* Initialize the session-stored changeset, if not set yet |
||||
* |
||||
* @param Table $table |
||||
* @return Changeset |
||||
*/ |
||||
private function getChangeset(Table $table) |
||||
{ |
||||
if (Input::has('reset')) { |
||||
session()->forget($table->draftSessionKey); |
||||
} |
||||
|
||||
/** @var Changeset $changeset */ |
||||
return session()->remember($table->draftSessionKey, function () use ($table) { |
||||
$changeset = new Changeset(); |
||||
$changeset->table = $table; |
||||
$changeset->revision = $table->revision; |
||||
return $changeset; |
||||
}); |
||||
} |
||||
|
||||
private function storeChangeset(Changeset $chs) |
||||
{ |
||||
session()->put($chs->table->draftSessionKey, $chs); |
||||
} |
||||
|
||||
/** |
||||
* Discard draft and redirect to table view |
||||
*/ |
||||
public function discard(User $user, string $table) |
||||
{ |
||||
/** @var Table $tableModel */ |
||||
$tableModel = $user->tables()->where('name', $table)->first(); |
||||
if ($tableModel === null) abort(404, "No such table."); |
||||
|
||||
session()->forget($tableModel->draftSessionKey); |
||||
|
||||
return redirect($tableModel->viewRoute); |
||||
} |
||||
|
||||
public function draft(User $user, string $table, $tab = null) |
||||
{ |
||||
/** @var Table $tableModel */ |
||||
$tableModel = $user->tables()->where('name', $table)->first(); |
||||
if ($tableModel === null) abort(404, "No such table."); |
||||
|
||||
if ($tab == null) $tab = 'edit-rows'; |
||||
$tabs = ['edit-rows', 'add-rows', 'manage-columns', 'review']; |
||||
if (!in_array($tab, $tabs)) abort(404, "No such tab: $tab"); |
||||
|
||||
$changeset = $this->getChangeset($tableModel); |
||||
|
||||
if (Input::has('dump')) { |
||||
dd($changeset); |
||||
} |
||||
|
||||
return $this->{camel_case($tab)}($changeset); |
||||
} |
||||
|
||||
/** @noinspection PhpUnusedPrivateMethodInspection */ |
||||
private function editRows(Changeset $changeset) |
||||
{ |
||||
$revision = $changeset->revision; |
||||
$columns = $changeset->fetchAndTransformColumns(); |
||||
$rows = $revision->rowsData($columns, true, false)->paginate(25, []); |
||||
|
||||
return view('table.propose.edit-rows', [ |
||||
'changeset' => $changeset, |
||||
'table' => $changeset->table, |
||||
'columns' => collect($columns), |
||||
'rows' => $rows, |
||||
]); |
||||
} |
||||
|
||||
/** @noinspection PhpUnusedPrivateMethodInspection */ |
||||
private function addRows(Changeset $changeset) |
||||
{ |
||||
$columns = $changeset->fetchAndTransformColumns(); |
||||
$rows = $changeset->getAddedRows(25); |
||||
|
||||
return view('table.propose.add-rows', [ |
||||
'changeset' => $changeset, |
||||
'table' => $changeset->table, |
||||
'columns' => collect($columns), |
||||
'rows' => $rows, |
||||
]); |
||||
} |
||||
|
||||
public function draftUpdate(Request $request, User $user, string $table) |
||||
{ |
||||
/** @var Table $tableModel */ |
||||
$tableModel = $user->tables()->where('name', $table)->first(); |
||||
if ($tableModel === null) abort(404, "No such table."); |
||||
|
||||
$changeset = $this->getChangeset($tableModel); |
||||
|
||||
$input = objBag($request->all(), false); |
||||
|
||||
try { |
||||
$code = 200; |
||||
switch ($input->action) { |
||||
case 'row.update': |
||||
$data = (object)$input->data; |
||||
$changeset->rowUpdate($data); |
||||
|
||||
$resp = $changeset->fetchAndTransformRow($data->_id); |
||||
break; |
||||
|
||||
case 'row.remove': |
||||
$isNew = $changeset->isNewRow($input->id); |
||||
$changeset->rowRemove($input->id); |
||||
$resp = $isNew ? null : $changeset->fetchAndTransformRow($input->id); |
||||
break; |
||||
|
||||
case 'row.restore': |
||||
$changeset->rowRestore($input->id); |
||||
$resp = $changeset->fetchAndTransformRow($input->id); |
||||
break; |
||||
|
||||
case 'rows.add': |
||||
$changeset->addBlankRows($input->count); |
||||
|
||||
// rows.add is sent via a form |
||||
if ($input->has('redirect')) { |
||||
return redirect($input->redirect); |
||||
} else { |
||||
$resp = null; |
||||
} |
||||
break; |
||||
|
||||
case 'rows.add-csv': |
||||
try { |
||||
$changeset->addFilledRows(Utils::csvToArray($input->data)); |
||||
} catch (\Exception $e) { |
||||
return $this->backWithErrors(['data' => $e->getMessage()]); |
||||
} |
||||
|
||||
// rows.add-csv is sent via a form |
||||
if ($input->has('redirect')) { |
||||
return redirect($input->redirect); |
||||
} else { |
||||
$resp = null; |
||||
} |
||||
break; |
||||
|
||||
default: |
||||
$resp = "Bad Action"; |
||||
$code = 400; |
||||
break; |
||||
} |
||||
} catch (SimpleValidationException $e) { |
||||
return $this->jsonResponse(['errors' => $e->getMessageBag()->getMessages()], 400); |
||||
} |
||||
|
||||
$this->storeChangeset($changeset); |
||||
|
||||
return $this->jsonResponse($resp, $code); |
||||
} |
||||
} |
@ -0,0 +1,76 @@
|
||||
<?php |
||||
|
||||
|
||||
namespace App\Tables; |
||||
|
||||
|
||||
abstract class BaseNumerator |
||||
{ |
||||
/** @var int */ |
||||
protected $next; |
||||
|
||||
/** @var int */ |
||||
protected $last; |
||||
|
||||
/** |
||||
* BaseNumerator constructor. |
||||
* |
||||
* @param int|int[] $first - first index, or [first, last] |
||||
* @param int|null $last - last index, or null |
||||
*/ |
||||
public function __construct($first, $last = null) |
||||
{ |
||||
if (is_array($first) && $last === null) { |
||||
list($first, $last) = $first; |
||||
} |
||||
|
||||
$this->next = $first; |
||||
$this->last = $last; |
||||
} |
||||
|
||||
/** |
||||
* Get next key, incrementing the internal state |
||||
* |
||||
* @return string |
||||
*/ |
||||
public function next() |
||||
{ |
||||
if (!$this->hasMore()) |
||||
throw new \OutOfBoundsException("Column numerator has run out of allocated GCID slots"); |
||||
|
||||
$key = $this->getKey($this->next); |
||||
$this->next++; |
||||
return $key; |
||||
} |
||||
|
||||
/** |
||||
* Convert numeric index to a key |
||||
* |
||||
* @param int $index |
||||
* @return mixed |
||||
*/ |
||||
protected function getKey($index) |
||||
{ |
||||
return $index; // simple default |
||||
} |
||||
|
||||
/** |
||||
* @return bool - true iof there are more keys available |
||||
*/ |
||||
protected function hasMore() |
||||
{ |
||||
return $this->next <= $this->last; |
||||
} |
||||
|
||||
/** |
||||
* Generate all keys |
||||
* |
||||
* @return \Generator |
||||
*/ |
||||
public function generate() |
||||
{ |
||||
while ($this->hasMore()) { |
||||
yield $this->next(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,467 @@
|
||||
<?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 ($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); |
||||
|
||||
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) { |
||||
$newOrder[] = $colsById[$id]; |
||||
} |
||||
|
||||
$leftover_keys = array_diff(array_keys($colsById), $this->columnOrder); |
||||
foreach ($leftover_keys as $id) { |
||||
$newOrder[] = $colsById[$id]; |
||||
} |
||||
|
||||
return $cachedColumns = $newOrder; |
||||
} |
||||
|
||||
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 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)) { |
||||
return (object)$this->newRows[$id]; |
||||
} |
||||
|
||||
$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 |
||||
*/ |
||||
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]); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 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'); |
||||
|
||||
$this->newRows = array_merge($this->newRows, $rows->all()); |
||||
} |
||||
} |
@ -0,0 +1,201 @@
|
||||
<?php |
||||
|
||||
return [ |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Debugbar Settings |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Debugbar is enabled by default, when debug is set to true in app.php. |
||||
| You can override the value by setting enable to true or false instead of null. |
||||
| |
||||
| You can provide an array of URI's that must be ignored (eg. 'api/*') |
||||
| |
||||
*/ |
||||
|
||||
'enabled' => env('DEBUGBAR_ENABLED', null), |
||||
'except' => [ |
||||
// |
||||
], |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Storage settings |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| DebugBar stores data for session/ajax requests. |
||||
| You can disable this, so the debugbar stores data in headers/session, |
||||
| but this can cause problems with large data collectors. |
||||
| By default, file storage (in the storage folder) is used. Redis and PDO |
||||
| can also be used. For PDO, run the package migrations first. |
||||
| |
||||
*/ |
||||
'storage' => [ |
||||
'enabled' => true, |
||||
'driver' => 'file', // redis, file, pdo, custom |
||||
'path' => storage_path('debugbar'), // For file driver |
||||
'connection' => null, // Leave null for default connection (Redis/PDO) |
||||
'provider' => '' // Instance of StorageInterface for custom driver |
||||
], |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Vendors |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Vendor files are included by default, but can be set to false. |
||||
| This can also be set to 'js' or 'css', to only include javascript or css vendor files. |
||||
| Vendor files are for css: font-awesome (including fonts) and highlight.js (css files) |
||||
| and for js: jquery and and highlight.js |
||||
| So if you want syntax highlighting, set it to true. |
||||
| jQuery is set to not conflict with existing jQuery scripts. |
||||
| |
||||
*/ |
||||
|
||||
'include_vendors' => true, |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Capture Ajax Requests |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| The Debugbar can capture Ajax requests and display them. If you don't want this (ie. because of errors), |
||||
| you can use this option to disable sending the data through the headers. |
||||
| |
||||
| Optionally, you can also send ServerTiming headers on ajax requests for the Chrome DevTools. |
||||
*/ |
||||
|
||||
'capture_ajax' => true, |
||||
'add_ajax_timing' => false, |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Custom Error Handler for Deprecated warnings |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| When enabled, the Debugbar shows deprecated warnings for Symfony components |
||||
| in the Messages tab. |
||||
| |
||||
*/ |
||||
'error_handler' => false, |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Clockwork integration |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| The Debugbar can emulate the Clockwork headers, so you can use the Chrome |
||||
| Extension, without the server-side code. It uses Debugbar collectors instead. |
||||
| |
||||
*/ |
||||
'clockwork' => false, |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| DataCollectors |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Enable/disable DataCollectors |
||||
| |
||||
*/ |
||||
|
||||
'collectors' => [ |
||||
'phpinfo' => true, // Php version |
||||
'messages' => true, // Messages |
||||
'time' => true, // Time Datalogger |
||||
'memory' => true, // Memory usage |
||||
'exceptions' => true, // Exception displayer |
||||
'log' => true, // Logs from Monolog (merged in messages if enabled) |
||||
'db' => true, // Show database (PDO) queries and bindings |
||||
'views' => true, // Views with their data |
||||
'route' => true, // Current route information |
||||
'auth' => true, // Display Laravel authentication status |
||||
'gate' => true, // Display Laravel Gate checks |
||||
'session' => true, // Display session data |
||||
'symfony_request' => true, // Only one can be enabled.. |
||||
'mail' => true, // Catch mail messages |
||||
'laravel' => false, // Laravel version and environment |
||||
'events' => false, // All events fired |
||||
'default_request' => false, // Regular or special Symfony request logger |
||||
'logs' => false, // Add the latest log messages |
||||
'files' => false, // Show the included files |
||||
'config' => false, // Display config settings |
||||
'cache' => false, // Display cache events |
||||
], |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Extra options |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Configure some DataCollectors |
||||
| |
||||
*/ |
||||
|
||||
'options' => [ |
||||
'auth' => [ |
||||
'show_name' => true, // Also show the users name/email in the debugbar |
||||
], |
||||
'db' => [ |
||||
'with_params' => true, // Render SQL with the parameters substituted |
||||
'backtrace' => true, // Use a backtrace to find the origin of the query in your files. |
||||
'timeline' => false, // Add the queries to the timeline |
||||
'explain' => [ // Show EXPLAIN output on queries |
||||
'enabled' => false, |
||||
'types' => ['SELECT'], // ['SELECT', 'INSERT', 'UPDATE', 'DELETE']; for MySQL 5.6.3+ |
||||
], |
||||
'hints' => true, // Show hints for common mistakes |
||||
], |
||||
'mail' => [ |
||||
'full_log' => false |
||||
], |
||||
'views' => [ |
||||
'data' => false, //Note: Can slow down the application, because the data can be quite large.. |
||||
], |
||||
'route' => [ |
||||
'label' => true // show complete route on bar |
||||
], |
||||
'logs' => [ |
||||
'file' => null |
||||
], |
||||
'cache' => [ |
||||
'values' => true // collect cache values |
||||
], |
||||
], |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Inject Debugbar in Response |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Usually, the debugbar is added just before </body>, by listening to the |
||||
| Response after the App is done. If you disable this, you have to add them |
||||
| in your template yourself. See http://phpdebugbar.com/docs/rendering.html |
||||
| |
||||
*/ |
||||
|
||||