rappasoft / laravel-livewire-tables

A dynamic table component for Laravel Livewire
https://rappasoft.com/docs/laravel-livewire-tables/v2/introduction
MIT License
1.71k stars 320 forks source link

[Bug]: enum columns don't work in v3 #1434

Closed nikosid closed 8 months ago

nikosid commented 9 months ago

What happened?

After upgrade to v3 I get the error: Rappasoft\LaravelLivewireTables\Views\Column::getContents(): Return value must be of type Illuminate\Support\HtmlString|Rappasoft\LaravelLivewireTables\Exceptions\DataTableConfigurationException|Illuminate\Contracts\Foundation\Application|Illuminate\Contracts\View\Factory|Illuminate\Contracts\View\View|string|null, App\Enums\UrlSource returned

This happens because I have this column configured: Column::make('Source', 'source')->sortable(),

In my model there is this cast:

protected $casts = [
        'source' => UrlSource::class,
    ];

and class UrlSource looks like this:

<?php

namespace App\Enums;

enum UrlSource: string
{
    case WEB = 'web';
    case API = 'api';
}

How to reproduce the bug

No response

Package Version

v3.0.0.-beta.4

PHP Version

8.2.x

Laravel Version

10.28.0

Alpine Version

No response

Theme

None

Notes

This worked in version 2*

Error Message

Rappasoft\LaravelLivewireTables\Views\Column::getContents(): Return value must be of type Illuminate\Support\HtmlString|Rappasoft\LaravelLivewireTables\Exceptions\DataTableConfigurationException|Illuminate\Contracts\Foundation\Application|Illuminate\Contracts\View\Factory|Illuminate\Contracts\View\View|string|null, App\Enums\UrlSource returned

danie-ramdhani commented 9 months ago

maybe using format works?

Column::make('Source', 'source')
->sortable()
->format(fn ($value) => $value->value)
lrljoe commented 9 months ago

Question - if I adjust the return type to accept an Enum, and use:

Column::make('Source', 'source')->sortable(),

I'll just get the value (i.e. not a name/label etc), is that your desired outcome?


If you want to access something else on the Enum class:

Let's wind it back a tiny bit! The Table Package will return fields, based on what is in your Table, and setAdditionalSelects.

When you use a "make" with a second value, it'll try to find that field in the model (or via a relation using dot notation). When it finds it, it adds that value into the Builder query, and will return that as a raw value, and it won't go through the typical model casting etc.

If you want to use an Enum Cast, and return a method on your Enum class (e.g. a label etc), then the way to achieve what you want is using:

1) A Label Column, and use the label method to tell the table what you want out of it, e.g.

  Column::make('Source')->sortable()
  ->label(
      fn($row, Column $column) => $row->source->name
  ),

or

  Column::make('Source')->sortable()
  ->label(
      fn($row, Column $column) => $row->source->value   
  ),

2) Adding the relevant field into the setAdditionalSelects() so that you have access to the raw value

public function configure(): void
{
    $this->setPrimaryKey('id')
            ->setAdditionalSelects(['articles.id as id', 'articles.source'])
}
lrljoe commented 9 months ago

So I've added the return type hint in, so that you won't receive the error, that's in v3-develop now, and will go into a new beta release in the next day or two.

Interested to know your use case for it though, and whether an EnumColumn or similar would be useful going forward (for example - allowing you to specify which method you want to call on the column).

lrljoe commented 8 months ago

Fix for return type is in v3.0.0-beta.5