diff --git a/src/Views/Columns/LivewireComponentColumn.php b/src/Views/Columns/LivewireComponentColumn.php index 0049c338a..4111a6728 100644 --- a/src/Views/Columns/LivewireComponentColumn.php +++ b/src/Views/Columns/LivewireComponentColumn.php @@ -16,40 +16,21 @@ class LivewireComponentColumn extends Column use LivewireComponentColumnConfiguration, LivewireComponentColumnHelpers; + /** + * The Livewire Component assigned to this Column + */ protected ?string $livewireComponent; + /** + * Gets the contents for current row + */ public function getContents(Model $row): null|string|HtmlString|DataTableConfigurationException|\Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View { - if (! $this->hasLivewireComponent()) { - throw new DataTableConfigurationException('You must define a Livewire Component for this column'); - } - - if ($this->isLabel()) { - throw new DataTableConfigurationException('You can not use a label column with a Livewire Component column'); - } - - $attributes = []; - $value = $this->getValue($row); - - if ($this->hasAttributesCallback()) { - $attributes = call_user_func($this->getAttributesCallback(), $value, $row, $this); - - if (! is_array($attributes)) { - throw new DataTableConfigurationException('The return type of callback must be an array'); - } - } - - $implodedAttributes = collect($attributes)->map(function ($value, $key) { - return ':'.$key.'="$'.$key.'"'; - })->implode(' '); - - return new HtmlString(Blade::render( - '', - [ - 'component' => $this->getLivewireComponent(), - ...$attributes, - ], - )); + $this->runPreChecks(); + + $attributes = $this->retrieveAttributes($row); + + return $this->getHtmlString($attributes, $this->getTable().'-'.$row->{$row->getKeyName()}); } } diff --git a/src/Views/Columns/Traits/Configuration/LivewireComponentColumnConfiguration.php b/src/Views/Columns/Traits/Configuration/LivewireComponentColumnConfiguration.php index 54b62de71..e5a168484 100644 --- a/src/Views/Columns/Traits/Configuration/LivewireComponentColumnConfiguration.php +++ b/src/Views/Columns/Traits/Configuration/LivewireComponentColumnConfiguration.php @@ -6,6 +6,9 @@ trait LivewireComponentColumnConfiguration { + /** + * Defines which component to use + */ public function component(string $livewireComponent): self { $this->livewireComponent = (Str::startsWith($livewireComponent, 'livewire:')) ? substr($livewireComponent, 9) : $livewireComponent; diff --git a/src/Views/Columns/Traits/Helpers/LivewireComponentColumnHelpers.php b/src/Views/Columns/Traits/Helpers/LivewireComponentColumnHelpers.php index f1c4cff1b..55bedf325 100644 --- a/src/Views/Columns/Traits/Helpers/LivewireComponentColumnHelpers.php +++ b/src/Views/Columns/Traits/Helpers/LivewireComponentColumnHelpers.php @@ -2,6 +2,11 @@ namespace Rappasoft\LaravelLivewireTables\Views\Columns\Traits\Helpers; +use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Facades\Blade; +use Illuminate\Support\HtmlString; +use Rappasoft\LaravelLivewireTables\Exceptions\DataTableConfigurationException; + trait LivewireComponentColumnHelpers { /** @@ -13,10 +18,84 @@ public function getLivewireComponent(): ?string } /** - * Determines whether a Component View has been set + * Determines whether a Livewire Component has been set */ public function hasLivewireComponent(): bool { return isset($this->livewireComponent); } + + /** + * Retrieves attributes based on callback + */ + protected function retrieveAttributes(Model $row): array + { + $value = $this->getValue($row); + + $attributes = ['value' => $value]; + + if ($this->hasAttributesCallback()) { + $attributes = call_user_func($this->getAttributesCallback(), $value, $row, $this); + + if (! is_array($attributes)) { + throw new DataTableConfigurationException('The return type of callback must be an array'); + } + } + + return $attributes; + } + + /** + * Runs pre-checks + */ + protected function runPreChecks(): bool + { + if (! $this->hasLivewireComponent()) { + throw new DataTableConfigurationException('You must define a Livewire Component for this column'); + + return false; + } + + if ($this->isLabel()) { + throw new DataTableConfigurationException('You can not use a label column with a Livewire Component column'); + + return false; + } + + return true; + } + + /** + * Implodes defined attributes to be used + */ + protected function implodeAttributes(array $attributes): string + { + return collect($attributes)->map(function ($value, $key) { + return ':'.$key.'="$'.$key.'"'; + })->implode(' '); + } + + /** + * getBlade Render + */ + protected function getBlade(array $attributes, string $key) + { + return Blade::render( + 'implodeAttributes($attributes).' />', + [ + 'component' => $this->getLivewireComponent(), + 'key' => $key, + ...$attributes, + ], + ); + } + + /** + * Gets HTML STring + */ + protected function getHtmlString(array $attributes, string $key): HtmlString + { + return new HtmlString($this->getBlade($attributes, $key)); + + } } diff --git a/tests/Http/Livewire/PetsTableWithLivewireColumn.php b/tests/Http/Livewire/PetsTableWithLivewireColumn.php new file mode 100644 index 000000000..5c0ba4d43 --- /dev/null +++ b/tests/Http/Livewire/PetsTableWithLivewireColumn.php @@ -0,0 +1,40 @@ +setPrimaryKey('id'); + } + + public function columns(): array + { + return [ + Column::make('ID', 'id') + ->sortable(), + Column::make('Name', 'name') + ->sortable(), + LivewireComponentColumn::make('LW', 'name') + ->component('test-livewire-column-component')->attributes(function ($columnValue, $row) { + return [ + 'type' => 'test', + 'name' => $row->name, + ]; + }), + ]; + } +} diff --git a/tests/Http/Livewire/TestComponent.php b/tests/Http/Livewire/TestComponent.php new file mode 100644 index 000000000..7fa31a7ba --- /dev/null +++ b/tests/Http/Livewire/TestComponent.php @@ -0,0 +1,27 @@ +testItem = $age * 110; + } + + /** + * Get the view / contents that represent the component. + */ + public function render(): View|Closure|string + { + return \Illuminate\Support\Facades\Blade::render( + '
'.($this->testItem ?? 'Unknown').'
'); + + } +} diff --git a/tests/Http/Livewire/TestLivewireColumnComponent.php b/tests/Http/Livewire/TestLivewireColumnComponent.php new file mode 100644 index 000000000..e154fb730 --- /dev/null +++ b/tests/Http/Livewire/TestLivewireColumnComponent.php @@ -0,0 +1,28 @@ +'. + '
Name:'.($this->name ?? 'Unknown').'
'. + '
Type:'.($this->type ?? 'Unknown').'
'. + '' + ); + + } +} diff --git a/tests/TestServiceProvider.php b/tests/TestServiceProvider.php index d3714c914..2e9753c25 100644 --- a/tests/TestServiceProvider.php +++ b/tests/TestServiceProvider.php @@ -11,6 +11,9 @@ class TestServiceProvider extends ServiceProvider public function boot(): void { Blade::component('test-component', TestComponent::class); + + \Livewire\Livewire::component('test-livewire-column-component', \Rappasoft\LaravelLivewireTables\Tests\Http\Livewire\TestLivewireColumnComponent::class); + $this->loadViewsFrom(__DIR__.'/views', 'livewire-tables-test'); } diff --git a/tests/Unit/Views/Columns/LivewireComponentColumnTest.php b/tests/Unit/Views/Columns/LivewireComponentColumnTest.php index ac9c5b0a0..4c8f48929 100644 --- a/tests/Unit/Views/Columns/LivewireComponentColumnTest.php +++ b/tests/Unit/Views/Columns/LivewireComponentColumnTest.php @@ -2,6 +2,7 @@ namespace Rappasoft\LaravelLivewireTables\Tests\Unit\Views\Columns; +use Illuminate\Database\Eloquent\Model; use PHPUnit\Framework\Attributes\Group; use Rappasoft\LaravelLivewireTables\Exceptions\DataTableConfigurationException; use Rappasoft\LaravelLivewireTables\Tests\Models\Pet; @@ -89,4 +90,83 @@ public function test_can_set_attribute_callback(): void $this->assertTrue(self::$columnInstance->hasAttributesCallback()); } + + public static function setup_with_public_methods() + { + \Livewire\Livewire::component('test-livewire-column-component', \Rappasoft\LaravelLivewireTables\Tests\Http\Livewire\TestLivewireColumnComponent::class); + + $row = Pet::find(1); + + $temp = (new class('name', 'name') extends LivewireComponentColumn + { + public function pubRetrieveAttributes(Model $row) + { + return $this->retrieveAttributes($row); + } + + public function pubImplodeAttributes(array $attributes) + { + return $this->implodeAttributes($attributes); + } + + public function pubGetBlade(array $attributes, string $key) + { + return $this->getBlade($attributes, $key); + } + + public function pubGetHtmlString(array $attributes, string $key) + { + return $this->getHtmlString($attributes, $key); + } + })->component('test-livewire-column-component')->attributes(function ($columnValue, $row) { + return [ + 'type' => 'test', + 'name' => $row->name, + ]; + }); + + $temp->setTable('test-table'); + + return $temp; + } + + public function test_can_get_attributes_correctly(): void + { + $row = Pet::find(1); + $temp = self::setup_with_public_methods(); + $key = 'test-table-'.$row->{$row->getKeyName()}; + + $this->assertSame(['type' => 'test', 'name' => 'Cartman'], $temp->pubRetrieveAttributes($row)); + + $this->assertSame(':type="$type" :name="$name"', $temp->pubImplodeAttributes($temp->pubRetrieveAttributes($row))); + } + + public function test_can_get_blade_correctly(): void + { + $row = Pet::find(1); + $temp = self::setup_with_public_methods(); + $key = 'test-table-'.$row->{$row->getKeyName()}; + + $this->assertStringContainsString('wire:snapshot="{"data":{"id":null,"name":"Cartman","value":null,"type":"test"}', $temp->pubGetBlade($temp->pubRetrieveAttributes($row), $key)); + + $this->assertStringContainsString('
Name:Cartman
Type:test
', $temp->pubGetBlade($temp->pubRetrieveAttributes($row), $key)); + } + + public function test_can_get_html_string_correctly(): void + { + $row = Pet::find(1); + $temp = self::setup_with_public_methods(); + $key = 'test-table-'.$row->{$row->getKeyName()}; + + $this->assertStringContainsString('
Name:Cartman
Type:test
', $temp->pubGetHtmlString($temp->pubRetrieveAttributes($row), $key)); + } + + public function test_can_get_contents_correctly(): void + { + $row = Pet::find(1); + $temp = self::setup_with_public_methods(); + $key = 'test-table-'.$row->{$row->getKeyName()}; + + $this->assertStringContainsString('
Name:Cartman
Type:test
', $temp->getContents($row)); + } } diff --git a/tests/Visuals/Columns/LivewireComponentColumnVisualsTest.php b/tests/Visuals/Columns/LivewireComponentColumnVisualsTest.php new file mode 100644 index 000000000..28868f8a4 --- /dev/null +++ b/tests/Visuals/Columns/LivewireComponentColumnVisualsTest.php @@ -0,0 +1,66 @@ +assertSeeHtmlInOrder([ + '
Name:Ben
Type:test
', + '
Name:Cartman
Type:test
', + ]); + + } + + public function test_icon_column_renders_correctly_with_asc_sort(): void + { + $temp = new class extends PetsTableWithLivewireColumn + { + public function configure(): void + { + parent::configure(); + + $this->setDefaultSort('name', 'asc'); + + } + }; + Livewire::test($temp) + ->assertSeeHtmlInOrder([ + '
Name:Ben
Type:test
', + '
Name:Cartman
Type:test
', + ]); + } + + public function test_icon_column_renders_correctly_with_desc_sort(): void + { + $temp = new class extends PetsTableWithLivewireColumn + { + public function configure(): void + { + parent::configure(); + + $this->setDefaultSort('name', 'desc'); + + } + }; + Livewire::test($temp) + ->assertSeeHtmlInOrder([ + '
Name:Cartman
Type:test
', + '
Name:Ben
Type:test
', + ]); + } +}