Skip to content

Commit 6f25fcc

Browse files
authored
Fixes for livewire component column (rappasoft#2245)
* Initial Commit * Fix styling * Initial Commit * Fix styling * Adjust test * Fix styling * Use test-livewire-column-component * Additional Tests for LivewireComponentColumn * Fix styling * Add getContents Test
1 parent c75c206 commit 6f25fcc

File tree

9 files changed

+338
-31
lines changed

9 files changed

+338
-31
lines changed

src/Views/Columns/LivewireComponentColumn.php

Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,40 +16,21 @@ class LivewireComponentColumn extends Column
1616
use LivewireComponentColumnConfiguration,
1717
LivewireComponentColumnHelpers;
1818

19+
/**
20+
* The Livewire Component assigned to this Column
21+
*/
1922
protected ?string $livewireComponent;
2023

24+
/**
25+
* Gets the contents for current row
26+
*/
2127
public function getContents(Model $row): null|string|HtmlString|DataTableConfigurationException|\Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
2228
{
23-
if (! $this->hasLivewireComponent()) {
24-
throw new DataTableConfigurationException('You must define a Livewire Component for this column');
25-
}
26-
27-
if ($this->isLabel()) {
28-
throw new DataTableConfigurationException('You can not use a label column with a Livewire Component column');
29-
}
30-
31-
$attributes = [];
32-
$value = $this->getValue($row);
33-
34-
if ($this->hasAttributesCallback()) {
35-
$attributes = call_user_func($this->getAttributesCallback(), $value, $row, $this);
36-
37-
if (! is_array($attributes)) {
38-
throw new DataTableConfigurationException('The return type of callback must be an array');
39-
}
40-
}
41-
42-
$implodedAttributes = collect($attributes)->map(function ($value, $key) {
43-
return ':'.$key.'="$'.$key.'"';
44-
})->implode(' ');
45-
46-
return new HtmlString(Blade::render(
47-
'<livewire:dynamic-component :component="$component" '.$implodedAttributes.' :wire:key="'.$row->{$row->getKeyName()}.'" />',
48-
[
49-
'component' => $this->getLivewireComponent(),
50-
...$attributes,
51-
],
52-
));
29+
$this->runPreChecks();
30+
31+
$attributes = $this->retrieveAttributes($row);
32+
33+
return $this->getHtmlString($attributes, $this->getTable().'-'.$row->{$row->getKeyName()});
5334

5435
}
5536
}

src/Views/Columns/Traits/Configuration/LivewireComponentColumnConfiguration.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
trait LivewireComponentColumnConfiguration
88
{
9+
/**
10+
* Defines which component to use
11+
*/
912
public function component(string $livewireComponent): self
1013
{
1114
$this->livewireComponent = (Str::startsWith($livewireComponent, 'livewire:')) ? substr($livewireComponent, 9) : $livewireComponent;

src/Views/Columns/Traits/Helpers/LivewireComponentColumnHelpers.php

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
namespace Rappasoft\LaravelLivewireTables\Views\Columns\Traits\Helpers;
44

5+
use Illuminate\Database\Eloquent\Model;
6+
use Illuminate\Support\Facades\Blade;
7+
use Illuminate\Support\HtmlString;
8+
use Rappasoft\LaravelLivewireTables\Exceptions\DataTableConfigurationException;
9+
510
trait LivewireComponentColumnHelpers
611
{
712
/**
@@ -13,10 +18,84 @@ public function getLivewireComponent(): ?string
1318
}
1419

1520
/**
16-
* Determines whether a Component View has been set
21+
* Determines whether a Livewire Component has been set
1722
*/
1823
public function hasLivewireComponent(): bool
1924
{
2025
return isset($this->livewireComponent);
2126
}
27+
28+
/**
29+
* Retrieves attributes based on callback
30+
*/
31+
protected function retrieveAttributes(Model $row): array
32+
{
33+
$value = $this->getValue($row);
34+
35+
$attributes = ['value' => $value];
36+
37+
if ($this->hasAttributesCallback()) {
38+
$attributes = call_user_func($this->getAttributesCallback(), $value, $row, $this);
39+
40+
if (! is_array($attributes)) {
41+
throw new DataTableConfigurationException('The return type of callback must be an array');
42+
}
43+
}
44+
45+
return $attributes;
46+
}
47+
48+
/**
49+
* Runs pre-checks
50+
*/
51+
protected function runPreChecks(): bool
52+
{
53+
if (! $this->hasLivewireComponent()) {
54+
throw new DataTableConfigurationException('You must define a Livewire Component for this column');
55+
56+
return false;
57+
}
58+
59+
if ($this->isLabel()) {
60+
throw new DataTableConfigurationException('You can not use a label column with a Livewire Component column');
61+
62+
return false;
63+
}
64+
65+
return true;
66+
}
67+
68+
/**
69+
* Implodes defined attributes to be used
70+
*/
71+
protected function implodeAttributes(array $attributes): string
72+
{
73+
return collect($attributes)->map(function ($value, $key) {
74+
return ':'.$key.'="$'.$key.'"';
75+
})->implode(' ');
76+
}
77+
78+
/**
79+
* getBlade Render
80+
*/
81+
protected function getBlade(array $attributes, string $key)
82+
{
83+
return Blade::render(
84+
'<livewire:dynamic-component :component="$component" :key="$key" '.$this->implodeAttributes($attributes).' />',
85+
[
86+
'component' => $this->getLivewireComponent(),
87+
'key' => $key,
88+
...$attributes,
89+
],
90+
);
91+
}
92+
93+
/**
94+
* Gets HTML STring
95+
*/
96+
protected function getHtmlString(array $attributes, string $key): HtmlString
97+
{
98+
return new HtmlString($this->getBlade($attributes, $key));
99+
100+
}
22101
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
namespace Rappasoft\LaravelLivewireTables\Tests\Http\Livewire;
4+
5+
use Illuminate\Support\Facades\App;
6+
use Rappasoft\LaravelLivewireTables\Tests\Models\Pet;
7+
use Rappasoft\LaravelLivewireTables\Views\Column;
8+
use Rappasoft\LaravelLivewireTables\Views\Columns\LivewireComponentColumn;
9+
10+
class PetsTableWithLivewireColumn extends BaseTable
11+
{
12+
public $model = Pet::class;
13+
14+
public function changeLocale(string $locale)
15+
{
16+
App::setLocale($locale);
17+
}
18+
19+
public function configure(): void
20+
{
21+
$this->setPrimaryKey('id');
22+
}
23+
24+
public function columns(): array
25+
{
26+
return [
27+
Column::make('ID', 'id')
28+
->sortable(),
29+
Column::make('Name', 'name')
30+
->sortable(),
31+
LivewireComponentColumn::make('LW', 'name')
32+
->component('test-livewire-column-component')->attributes(function ($columnValue, $row) {
33+
return [
34+
'type' => 'test',
35+
'name' => $row->name,
36+
];
37+
}),
38+
];
39+
}
40+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace Rappasoft\LaravelLivewireTables\Tests\Http;
4+
5+
use Closure;
6+
use Illuminate\Contracts\View\View;
7+
use Illuminate\View\Component;
8+
9+
class TestComponent extends Component
10+
{
11+
public int $testItem = 0;
12+
13+
public function __construct(int $age)
14+
{
15+
$this->testItem = $age * 110;
16+
}
17+
18+
/**
19+
* Get the view / contents that represent the component.
20+
*/
21+
public function render(): View|Closure|string
22+
{
23+
return \Illuminate\Support\Facades\Blade::render(
24+
'<div>'.($this->testItem ?? 'Unknown').'</div>');
25+
26+
}
27+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace Rappasoft\LaravelLivewireTables\Tests\Http\Livewire;
4+
5+
class TestLivewireColumnComponent extends \Livewire\Component
6+
{
7+
public string $id;
8+
9+
public string $name;
10+
11+
public string $value;
12+
13+
public string $type;
14+
15+
/**
16+
* Get the view / contents that represent the component.
17+
*/
18+
public function render()
19+
{
20+
return \Illuminate\Support\Facades\Blade::render(
21+
'<div>'.
22+
'<div>Name:'.($this->name ?? 'Unknown').'</div>'.
23+
'<div>Type:'.($this->type ?? 'Unknown').'</div>'.
24+
'</div>'
25+
);
26+
27+
}
28+
}

tests/TestServiceProvider.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ class TestServiceProvider extends ServiceProvider
1111
public function boot(): void
1212
{
1313
Blade::component('test-component', TestComponent::class);
14+
15+
\Livewire\Livewire::component('test-livewire-column-component', \Rappasoft\LaravelLivewireTables\Tests\Http\Livewire\TestLivewireColumnComponent::class);
16+
1417
$this->loadViewsFrom(__DIR__.'/views', 'livewire-tables-test');
1518

1619
}

tests/Unit/Views/Columns/LivewireComponentColumnTest.php

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Rappasoft\LaravelLivewireTables\Tests\Unit\Views\Columns;
44

5+
use Illuminate\Database\Eloquent\Model;
56
use PHPUnit\Framework\Attributes\Group;
67
use Rappasoft\LaravelLivewireTables\Exceptions\DataTableConfigurationException;
78
use Rappasoft\LaravelLivewireTables\Tests\Models\Pet;
@@ -89,4 +90,83 @@ public function test_can_set_attribute_callback(): void
8990

9091
$this->assertTrue(self::$columnInstance->hasAttributesCallback());
9192
}
93+
94+
public static function setup_with_public_methods()
95+
{
96+
\Livewire\Livewire::component('test-livewire-column-component', \Rappasoft\LaravelLivewireTables\Tests\Http\Livewire\TestLivewireColumnComponent::class);
97+
98+
$row = Pet::find(1);
99+
100+
$temp = (new class('name', 'name') extends LivewireComponentColumn
101+
{
102+
public function pubRetrieveAttributes(Model $row)
103+
{
104+
return $this->retrieveAttributes($row);
105+
}
106+
107+
public function pubImplodeAttributes(array $attributes)
108+
{
109+
return $this->implodeAttributes($attributes);
110+
}
111+
112+
public function pubGetBlade(array $attributes, string $key)
113+
{
114+
return $this->getBlade($attributes, $key);
115+
}
116+
117+
public function pubGetHtmlString(array $attributes, string $key)
118+
{
119+
return $this->getHtmlString($attributes, $key);
120+
}
121+
})->component('test-livewire-column-component')->attributes(function ($columnValue, $row) {
122+
return [
123+
'type' => 'test',
124+
'name' => $row->name,
125+
];
126+
});
127+
128+
$temp->setTable('test-table');
129+
130+
return $temp;
131+
}
132+
133+
public function test_can_get_attributes_correctly(): void
134+
{
135+
$row = Pet::find(1);
136+
$temp = self::setup_with_public_methods();
137+
$key = 'test-table-'.$row->{$row->getKeyName()};
138+
139+
$this->assertSame(['type' => 'test', 'name' => 'Cartman'], $temp->pubRetrieveAttributes($row));
140+
141+
$this->assertSame(':type="$type" :name="$name"', $temp->pubImplodeAttributes($temp->pubRetrieveAttributes($row)));
142+
}
143+
144+
public function test_can_get_blade_correctly(): void
145+
{
146+
$row = Pet::find(1);
147+
$temp = self::setup_with_public_methods();
148+
$key = 'test-table-'.$row->{$row->getKeyName()};
149+
150+
$this->assertStringContainsString('wire:snapshot="{&quot;data&quot;:{&quot;id&quot;:null,&quot;name&quot;:&quot;Cartman&quot;,&quot;value&quot;:null,&quot;type&quot;:&quot;test&quot;}', $temp->pubGetBlade($temp->pubRetrieveAttributes($row), $key));
151+
152+
$this->assertStringContainsString('<div>Name:Cartman</div><div>Type:test</div>', $temp->pubGetBlade($temp->pubRetrieveAttributes($row), $key));
153+
}
154+
155+
public function test_can_get_html_string_correctly(): void
156+
{
157+
$row = Pet::find(1);
158+
$temp = self::setup_with_public_methods();
159+
$key = 'test-table-'.$row->{$row->getKeyName()};
160+
161+
$this->assertStringContainsString('<div>Name:Cartman</div><div>Type:test</div>', $temp->pubGetHtmlString($temp->pubRetrieveAttributes($row), $key));
162+
}
163+
164+
public function test_can_get_contents_correctly(): void
165+
{
166+
$row = Pet::find(1);
167+
$temp = self::setup_with_public_methods();
168+
$key = 'test-table-'.$row->{$row->getKeyName()};
169+
170+
$this->assertStringContainsString('<div>Name:Cartman</div><div>Type:test</div>', $temp->getContents($row));
171+
}
92172
}

0 commit comments

Comments
 (0)