• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Okipa / laravel-table / #1458

16 Nov 2023 11:01AM UTC coverage: 87.209%. Remained the same
#1458

push

php-coveralls

Okipa
* Bumped dependencies
* Fixed PHPStan analysis

21 of 21 new or added lines in 9 files covered. (100.0%)

6 existing lines in 2 files now uncovered.

975 of 1118 relevant lines covered (87.21%)

24.48 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.84
/src/Livewire/Table.php
1
<?php
2

3
namespace Okipa\LaravelTable\Livewire;
4

5
use Illuminate\Contracts\View\View;
6
use Illuminate\Database\Eloquent\Model;
7
use Illuminate\Support\Arr;
8
use Illuminate\Support\Str;
9
use JsonException;
10
use Livewire\Component;
11
use Livewire\WithPagination;
12
use Okipa\LaravelTable\Abstracts\AbstractBulkAction;
13
use Okipa\LaravelTable\Abstracts\AbstractColumnAction;
14
use Okipa\LaravelTable\Abstracts\AbstractHeadAction;
15
use Okipa\LaravelTable\Abstracts\AbstractRowAction;
16
use Okipa\LaravelTable\Abstracts\AbstractTableConfiguration;
17
use Okipa\LaravelTable\Exceptions\InvalidTableConfiguration;
18
use Okipa\LaravelTable\Exceptions\UnrecognizedActionType;
19

20
/**
21
 * @SuppressWarnings(PHPMD.TooManyFields)
22
 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
23
 */
24
class Table extends Component
25
{
26
    use WithPagination;
27

28
    public bool $initialized = false;
29

30
    public string $config;
31

32
    public array $configParams = [];
33

34
    public \Okipa\LaravelTable\Table $table;
35

36
    public string $paginationTheme = 'bootstrap';
37

38
    public string $searchBy = '';
39

40
    public string $searchableLabels;
41

42
    public bool $searchInProgress;
43

44
    public int $numberOfRowsPerPage;
45

46
    public null|string $sortBy;
47

48
    public null|string $sortDir;
49

50
    public array $reorderConfig = [];
51

52
    public array $selectedFilters = [];
53

54
    public bool $resetFilters = false;
55

56
    public array $headActionArray;
57

58
    public bool $selectAll = false;
59

60
    public array $selectedModelKeys = [];
61

62
    public array $tableBulkActionsArray;
63

64
    public array $tableRowActionsArray;
65

66
    public array $tableColumnActionsArray;
67

68
    protected $listeners = [
69
        'laraveltable:filters:wire:ignore:cancel' => 'cancelWireIgnoreOnFilters',
70
        'laraveltable:action:confirmed' => 'actionConfirmed',
71
        'laraveltable:refresh' => 'refresh',
72
    ];
73

74
    public function init(): void
75
    {
76
        $this->initPaginationTheme();
130✔
77
        $this->initialized = true;
130✔
78
    }
79

80
    protected function initPaginationTheme(): void
81
    {
82
        $this->paginationTheme = Str::contains(config('laravel-table.ui'), 'bootstrap')
130✔
83
            ? 'bootstrap'
130✔
UNCOV
84
            : 'tailwind';
×
85
    }
86

87
    /**
88
     * @throws \Okipa\LaravelTable\Exceptions\InvalidTableConfiguration
89
     * @throws \Okipa\LaravelTable\Exceptions\NoColumnsDeclared
90
     * @throws JsonException
91
     */
92
    public function render(): View
93
    {
94
        $config = $this->buildConfig();
138✔
95

96
        return view('laravel-table::' . config('laravel-table.ui') . '.table', $this->buildTable($config));
136✔
97
    }
98

99
    /** @throws \Okipa\LaravelTable\Exceptions\InvalidTableConfiguration */
100
    protected function buildConfig(): AbstractTableConfiguration
101
    {
102

103
        $config = app($this->config);
138✔
104
        if (! $config instanceof AbstractTableConfiguration) {
138✔
105
            throw new InvalidTableConfiguration($this->config);
2✔
106
        }
107
        foreach ($this->configParams as $key => $value) {
136✔
108
            $config->{$key} = $value;
6✔
109
        }
110

111
        return $config;
136✔
112
    }
113

114
    /**
115
     * @throws \Okipa\LaravelTable\Exceptions\NoColumnsDeclared
116
     * @throws JsonException
117
     */
118
    protected function buildTable(AbstractTableConfiguration $config): array
119
    {
120
        $table = $config->setup();
136✔
121
        // Events triggering on load
122
        $table->triggerEventsEmissionOnLoad($this);
136✔
123
        // Prepend reorder column
124
        $table->prependReorderColumn();
136✔
125
        // Search
126
        $this->searchableLabels = $table->getSearchableLabels();
136✔
127
        // Sort
128
        $columnSortedByDefault = $table->getColumnSortedByDefault();
134✔
129
        $this->sortBy = $table->getOrderColumn()?->getAttribute()
134✔
130
            ?: ($this->sortBy ?? $columnSortedByDefault?->getAttribute());
118✔
131
        $this->sortDir ??= $columnSortedByDefault?->getSortDirByDefault();
134✔
132
        $sortableClosure = $this->sortBy && ! $table->getOrderColumn()
134✔
133
            ? $table->getColumn($this->sortBy)->getSortableClosure()
12✔
134
            : null;
122✔
135
        // Paginate
136
        $numberOfRowsPerPageOptions = $table->getNumberOfRowsPerPageOptions();
134✔
137
        $this->numberOfRowsPerPage ??= Arr::first($numberOfRowsPerPageOptions);
134✔
138
        // Filters
139
        $filtersArray = $table->generateFiltersArray();
134✔
140
        $filterClosures = $table->getFilterClosures($filtersArray, $this->selectedFilters);
134✔
141
        // Query preparation
142
        $query = $table->prepareQuery(
134✔
143
            $filterClosures,
134✔
144
            $this->searchBy,
134✔
145
            $sortableClosure ?: $this->sortBy,
134✔
146
            $this->sortDir,
134✔
147
        );
134✔
148
        // Rows generation
149
        $table->paginateRows($query, $this->numberOfRowsPerPage);
134✔
150
        // Results computing
151
        $table->computeResults($table->getRows()->getCollection());
134✔
152
        // Head action
153
        $this->headActionArray = $table->getHeadActionArray();
134✔
154
        // Bulk actions
155
        if (in_array($this->selectedModelKeys, [['selectAll'], ['unselectAll']], true)) {
134✔
156
            $this->selectedModelKeys = $this->selectedModelKeys === ['selectAll']
2✔
157
                ? $table->getRows()->map(fn (Model $model) => (string) $model->getKey())->toArray()
2✔
158
                : [];
2✔
159
        }
160
        $this->tableBulkActionsArray = $table->generateBulkActionsArray($this->selectedModelKeys);
134✔
161
        // Row actions
162
        $this->tableRowActionsArray = $table->generateRowActionsArray();
134✔
163
        // Column actions
164
        $this->tableColumnActionsArray = $table->generateColumnActionsArray();
134✔
165
        // Reorder config
166
        $this->reorderConfig = $table->getReorderConfig($this->sortDir);
134✔
167

168
        return [
134✔
169
            'columns' => $table->getColumns(),
134✔
170
            'columnsCount' => ($this->tableBulkActionsArray ? 1 : 0)
134✔
171
                + $table->getColumns()->count()
134✔
172
                + ($this->tableRowActionsArray ? 1 : 0),
134✔
173
            'rows' => $table->getRows(),
134✔
174
            'orderColumn' => $table->getOrderColumn(),
134✔
175
            'filtersArray' => $filtersArray,
134✔
176
            'numberOfRowsPerPageChoiceEnabled' => $table->isNumberOfRowsPerPageChoiceEnabled(),
134✔
177
            'numberOfRowsPerPageOptions' => $numberOfRowsPerPageOptions,
134✔
178
            'tableRowClass' => $table->getRowClass(),
134✔
179
            'results' => $table->getResults(),
134✔
180
            'navigationStatus' => $table->getNavigationStatus(),
134✔
181
        ];
134✔
182
    }
183

184
    public function reorder(array $newPositions): void
185
    {
186
        [
12✔
187
            'modelClass' => $modelClass,
12✔
188
            'reorderAttribute' => $reorderAttribute,
12✔
189
            'sortDir' => $sortDir,
12✔
190
            'beforeReorderAllModelKeysWithPosition' => $beforeReorderAllModelKeysWithPositionRawArray,
12✔
191
        ] = $this->reorderConfig;
12✔
192
        $beforeReorderAllModelKeysWithPositionCollection = collect($beforeReorderAllModelKeysWithPositionRawArray)
12✔
193
            ->sortBy(callback: 'position', descending: $sortDir === 'desc');
12✔
194
        $afterReorderModelKeysWithPositionCollection = collect($newPositions)
12✔
195
            ->sortBy('order')
12✔
196
            ->map(fn (array $newPosition) => [
12✔
197
                'modelKey' => $newPosition['value'],
12✔
198
                'position' => $beforeReorderAllModelKeysWithPositionCollection->firstWhere(
12✔
199
                    'modelKey',
12✔
200
                    $newPosition['value']
12✔
201
                )['position'],
12✔
202
            ]);
12✔
203
        $beforeReorderModelKeysWithPositionCollection = $afterReorderModelKeysWithPositionCollection
12✔
204
            ->map(fn (array $afterReorderModelKeyWithPosition) => $beforeReorderAllModelKeysWithPositionCollection
12✔
205
                ->firstWhere('modelKey', $afterReorderModelKeyWithPosition['modelKey']))
12✔
206
            ->sortBy(callback: 'position', descending: $sortDir === 'desc');
12✔
207
        $beforeReorderModelKeysWithIndexCollection = $beforeReorderModelKeysWithPositionCollection->pluck('modelKey');
12✔
208
        $afterReorderModelKeysWithIndexCollection = $afterReorderModelKeysWithPositionCollection->pluck('modelKey');
12✔
209
        $reorderedPositions = collect();
12✔
210
        foreach ($beforeReorderAllModelKeysWithPositionCollection as $beforeReorderModelKeysWithPosition) {
12✔
211
            $modelKey = $beforeReorderModelKeysWithPosition['modelKey'];
12✔
212
            $indexAfterReordering = $afterReorderModelKeysWithIndexCollection->search($modelKey);
12✔
213
            if ($indexAfterReordering === false) {
12✔
214
                $currentPosition = $beforeReorderAllModelKeysWithPositionCollection->firstWhere(
12✔
215
                    'modelKey',
12✔
216
                    $modelKey
12✔
217
                )['position'];
12✔
218
                $reorderedPositions->push(['modelKey' => $modelKey, 'position' => $currentPosition]);
12✔
219

220
                continue;
12✔
221
            }
222
            $modelKeyCurrentOneWillReplace = $beforeReorderModelKeysWithIndexCollection->get($indexAfterReordering);
12✔
223
            $newPosition = $beforeReorderAllModelKeysWithPositionCollection->firstWhere(
12✔
224
                'modelKey',
12✔
225
                $modelKeyCurrentOneWillReplace
12✔
226
            )['position'];
12✔
227
            $reorderedPositions->push(['modelKey' => $modelKey, 'position' => $newPosition]);
12✔
228
        }
229
        $startOrder = 1;
12✔
230
        foreach ($reorderedPositions->sortBy('position') as $reorderedPosition) {
12✔
231
            app($modelClass)->find($reorderedPosition['modelKey'])->update([$reorderAttribute => $startOrder++]);
12✔
232
        }
233
        $this->emit('laraveltable:action:feedback', __('The list has been reordered.'));
12✔
234
    }
235

236
    public function changeNumberOfRowsPerPage(int $numberOfRowsPerPage): void
237
    {
238
        $this->numberOfRowsPerPage = $numberOfRowsPerPage;
2✔
239
    }
240

241
    public function sortBy(string $columnKey): void
242
    {
243
        $this->sortDir = $this->sortBy !== $columnKey || $this->sortDir === 'desc'
8✔
244
            ? 'asc'
6✔
245
            : 'desc';
6✔
246
        $this->sortBy = $columnKey;
8✔
247
    }
248

249
    public function headAction(): mixed
250
    {
251
        if (! $this->headActionArray) {
4✔
252
            return null;
2✔
253
        }
254
        $headActionInstance = AbstractHeadAction::make($this->headActionArray);
2✔
255
        if (! $headActionInstance->isAllowed()) {
2✔
UNCOV
256
            return null;
×
257
        }
258

259
        return $headActionInstance->action($this);
2✔
260
    }
261

262
    public function updatedSelectAll(): void
263
    {
264
        $this->selectedModelKeys = $this->selectAll ? ['selectAll'] : ['unselectAll'];
2✔
265
    }
266

267
    public function resetFilters(): void
268
    {
269
        $this->selectedFilters = [];
2✔
270
        $this->resetFilters = true;
2✔
271
        $this->emitSelf('laraveltable:filters:wire:ignore:cancel');
2✔
272
    }
273

274
    public function cancelWireIgnoreOnFilters(): void
275
    {
276
        $this->resetFilters = false;
2✔
277
    }
278

279
    /** @throws \Okipa\LaravelTable\Exceptions\UnrecognizedActionType */
280
    public function actionConfirmed(string $actionType, string $identifier, null|string $modelKey): mixed
281
    {
282
        return match ($actionType) {
10✔
283
            'bulkAction' => $this->bulkAction($identifier, false),
10✔
284
            'rowAction' => $this->rowAction($identifier, $modelKey, false),
10✔
285
            'columnAction' => $this->columnAction($identifier, $modelKey, false),
10✔
286
            default => throw new UnrecognizedActionType($actionType),
10✔
287
        };
10✔
288
    }
289

290
    public function bulkAction(string $identifier, bool $requiresConfirmation): mixed
291
    {
292
        $bulkActionArray = AbstractBulkAction::retrieve($this->tableBulkActionsArray, $identifier);
8✔
293
        $bulkActionInstance = AbstractBulkAction::make($bulkActionArray);
8✔
294
        if (! $bulkActionInstance->allowedModelKeys) {
8✔
295
            return null;
2✔
296
        }
297
        if ($requiresConfirmation) {
6✔
298
            return $this->emit(
4✔
299
                'laraveltable:action:confirm',
4✔
300
                'bulkAction',
4✔
301
                $identifier,
4✔
302
                null,
4✔
303
                $bulkActionInstance->getConfirmationQuestion()
4✔
304
            );
4✔
305
        }
306
        $feedbackMessage = $bulkActionInstance->getFeedbackMessage();
6✔
307
        if ($feedbackMessage) {
6✔
308
            $this->emit('laraveltable:action:feedback', $feedbackMessage);
4✔
309
        }
310
        $models = app($bulkActionInstance->modelClass)->findMany($bulkActionInstance->allowedModelKeys);
6✔
311

312
        return $bulkActionInstance->action($models, $this);
6✔
313
    }
314

315
    public function rowAction(string $identifier, string $modelKey, bool $requiresConfirmation): mixed
316
    {
317
        $rowActionsArray = AbstractRowAction::retrieve($this->tableRowActionsArray, $modelKey);
5✔
318
        if (! $rowActionsArray) {
5✔
319
            return null;
1✔
320
        }
321
        $rowActionArray = collect($rowActionsArray)->where('identifier', $identifier)->first();
4✔
322
        $rowActionInstance = AbstractRowAction::make($rowActionArray);
4✔
323
        if (! $rowActionInstance->isAllowed()) {
4✔
UNCOV
324
            return null;
×
325
        }
326
        $model = app($rowActionArray['modelClass'])->findOrFail($modelKey);
4✔
327
        if ($requiresConfirmation) {
4✔
328
            return $this->emit(
2✔
329
                'laraveltable:action:confirm',
2✔
330
                'rowAction',
2✔
331
                $identifier,
2✔
332
                $modelKey,
2✔
333
                $rowActionInstance->getConfirmationQuestion($model)
2✔
334
            );
2✔
335
        }
336
        $feedbackMessage = $rowActionInstance->getFeedbackMessage($model);
4✔
337
        if ($feedbackMessage) {
4✔
338
            $this->emit('laraveltable:action:feedback', $feedbackMessage);
2✔
339
        }
340

341
        return $rowActionInstance->action($model, $this);
4✔
342
    }
343

344
    public function columnAction(string $identifier, string $modelKey, bool $requiresConfirmation): mixed
345
    {
346
        $columnActionArray = AbstractColumnAction::retrieve($this->tableColumnActionsArray, $modelKey, $identifier);
6✔
347
        if (! $columnActionArray) {
6✔
UNCOV
348
            return null;
×
349
        }
350
        $columnActionInstance = AbstractColumnAction::make($columnActionArray);
6✔
351
        if (! $columnActionInstance->isAllowed()) {
6✔
352
            return null;
2✔
353
        }
354
        $model = app($columnActionArray['modelClass'])->findOrFail($modelKey);
4✔
355
        if ($requiresConfirmation) {
4✔
356
            return $this->emit(
2✔
357
                'laraveltable:action:confirm',
2✔
358
                'columnAction',
2✔
359
                $identifier,
2✔
360
                $modelKey,
2✔
361
                $columnActionInstance->getConfirmationQuestion($model, $identifier)
2✔
362
            );
2✔
363
        }
364
        $feedbackMessage = $columnActionInstance->getFeedbackMessage($model, $identifier);
4✔
365
        if ($feedbackMessage) {
4✔
366
            $this->emit('laraveltable:action:feedback', $feedbackMessage);
2✔
367
        }
368

369
        return $columnActionInstance->action($model, $identifier, $this);
4✔
370
    }
371

372
    public function refresh(array $configParams = [], array $targetedConfigs = []): void
373
    {
374
        if ($targetedConfigs && ! in_array($this->config, $targetedConfigs, true)) {
2✔
375
            return;
2✔
376
        }
377
        $this->configParams = [...$this->configParams, ...$configParams];
2✔
378
        $this->emitSelf('$refresh');
2✔
379
    }
380
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc