platform
platform copied to clipboard
Filtering string column (Input) with comma in value throws and error
Describe the bug Add table with TD column and Input::make() filter. Then filter that column with comma in value. HttpFilter method parseHttpValue would then split that query parameter into array and whole rendering of column header throws an error
Expected behavior Column is filtered by string value without any errors. Comma is part of the filter value.
Screenshots

Server (please complete the following information):
- Platfrom Version: 13.7.1
- Laravel Version: 9
- PHP Version: 8.0
- Database: MSSQL
Additional context I guess that split by comma (,) is used for some other filters. There should be a way to exclude that if you have normal Input filter.
I also encountered this error. After a short brainstorming session, I found a solution that can help you until this bug is fixed:
First step:
I found out the scope "filters" which implemented in trait Filterable creates object of HttpFilter OR uses object of class which extends HttpFilter. So, we can use it to modify behavior of the scope. We need to create new class (I just created new class and copied a constructor and a method parseHttpValue to override them:
class HttpFilter extends \Orchid\Filters\HttpFilter {
public function __construct( Request $request = null, array $expects = [] ) {
$this->request = $request ?? request();
$this->filters = $this->request->collect('filter')
->map(fn ($item, $key) => $this->parseHttpValue($item, $expects[$key] ?? null))
->filter(fn ($item) => $item !== null);
$this->sorts = collect($this->request->get('sort', []));
}
/**
* @override
*
* @param string|null|array $query
*
* @return string|array|null
*/
protected function parseHttpValue( $query, string $expectedType = null )
{
if ( is_string($query) && 'string' !== $expectedType ) {
$item = explode(',', $query);
if ( count($item) > 1 ) {
return $item;
}
}
return $query;
}
}
I added array $expects into constructor signature. This is necessary to clearly indicate our intentions:
$filter = new HttpFilter( expects: ['title' => 'string'] );
So, we can use our new filter with the scope "filters":
Model::query()
->filters(httpFilter: $filter)
->paginate();
Second step:
Filter in the table uses HttpFilter which is used in get_filter (a global helper function). I found two options:
- Extend the Field
- Use
addBeforeRendermethod of target input to control the value First solution:
class Input extends \Orchid\Screen\Fields\Input {
/**
* @override
*
* @param mixed $value
*
* @return static
*/
public function value( $value ) : self
{
return $this;
}
/**
* @override
*
* @param string|null $name
*
* @return static
*/
public static function make( ?string $filterColumnName = null ) : self
{
return (new static)->name('')->set('value', $_GET['filter'][$filterColumnName ?? ''] ?? null);
}
}
We forbid all modifications of value.
Second solution lazier:
TD::make('title', __('admin/general.title'))
->filter(Input::make()->addBeforeRender(function () { // We can change the value of input before it's rendered
$this->value($_GET['filter']['title'] ?? '');
}))
So it works 🤗 I hope it will be useful for somebody. PS: sorry for my poor language