Skip to content

Commit

Permalink
[FIX] summarizeFormat() - Format leaking across columns (#1530)
Browse files Browse the repository at this point in the history
* fix summary leaking formatting across columns

* test summary formatting across columns
  • Loading branch information
dansysanalyst authored May 6, 2024
1 parent 4cff0b1 commit c855c70
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 24 deletions.
43 changes: 30 additions & 13 deletions src/ProcessDataSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -342,41 +342,58 @@ private function applySummaries(MorphToMany|EloquentBuilder|BaseCollection|Query
return;
}

$format = function ($summarize, $column, $field, $value) {
$applySummaryFormat = function ($summarizeMethod, $column, $field, $value) {
if (method_exists($this->component, 'summarizeFormat')) {
$summarizeFormat = $this->component->summarizeFormat();
$summarizeFormatTasks = $this->component->summarizeFormat();

if (count($summarizeFormat) === 0) {
data_set($column, 'summarize.' . $summarize, $value);
if (count($summarizeFormatTasks) === 0) {
data_set($column, 'summarize.' . $summarizeMethod, $value);

return;
}

foreach ($summarizeFormat as $field => $format) {
$parts = explode('.', $field);
foreach ($summarizeFormatTasks as $field => $applySummaryFormat) {
$fieldAndSummarizeMethods = explode('.', $field);

if (isset($parts[1])) {
$formats = str($parts[1])->replace(['{', '}'], '');
$allowedSummarizeFormats = explode(',', $formats);
if (count($fieldAndSummarizeMethods) != 2) {
throw new \InvalidArgumentException('Summary Formatter expects key "column_name.{summarize_method}", [' . $field . '] given instead.');
}

$fieldName = $fieldAndSummarizeMethods[0];
$sumarizeMethods = $fieldAndSummarizeMethods[1];

$applyFormatToSummarizeMethods = str($sumarizeMethods)->replaceMatches('/\s+/', '')
->replace(['{', '}'], '')
->explode(',')
->toArray();

if (in_array($summarizeMethod, $applyFormatToSummarizeMethods)) {
$formattingClosure = $this->component->summarizeFormat()[$field];

if (in_array($summarize, $allowedSummarizeFormats)) {
data_set($column, 'summarize.' . $summarize, $this->component->summarizeFormat()[$field]($value));
if (!is_callable($formattingClosure)) {
throw new \InvalidArgumentException('Summary Formatter expects a callable function, ' . gettype($formattingClosure) . ' given instead.');
}

if (in_array($fieldName, [$column->field, $column->dataField])) {
$value = $formattingClosure($value);
}

data_set($column, 'summarize.' . $summarizeMethod, $value);
}
}
}
};

$this->component->columns = collect($this->component->columns)
->map(function (array|\stdClass|Column $column) use ($results, $format) {
->map(function (array|\stdClass|Column $column) use ($results, $applySummaryFormat) {
$field = strval(data_get($column, 'dataField')) ?: strval(data_get($column, 'field'));

$summaries = ['sum', 'count', 'avg', 'min', 'max'];

foreach ($summaries as $summary) {
if (data_get($column, $summary . '.header') || data_get($column, $summary . '.footer')) {
$value = $results->{$summary}($field);
$format($summary, $column, $field, $value);
$applySummaryFormat($summary, $column, $field, $value);
}
}

Expand Down
11 changes: 10 additions & 1 deletion tests/Concerns/Components/DishesCalculationsTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public function fields(): PowerGridFields
return PowerGrid::fields()
->add('id')
->add('name')
->add('calories', fn ($dish) => $dish->calories . ' kcal')
->add('price');
}

Expand All @@ -84,6 +85,10 @@ public function columns(): array
->searchable()
->field('name'),

Column::make('Calories', 'calories', 'calories')
->withAvg('Average', header: true, footer: false)
->sortable(),

Column::add()
->title(__('Price'))
->field('price')
Expand All @@ -99,12 +104,16 @@ public function columns(): array

public function summarizeFormat(): array
{
$fmt = (new \NumberFormatter('pt-PT', \NumberFormatter::DEFAULT_STYLE));

return [
'price.{sum,avg,min,max}' => function ($value) {
return (new \NumberFormatter('en_US', \NumberFormatter::CURRENCY))
->formatCurrency($value, 'USD');
},
'price.{count}' => fn ($value) => $value,
'price.{count}' => fn ($value) => $fmt->format($value) . ' item(s)',
'calories.{avg}' => fn ($value) => $fmt->format($value) . ' kcal',

];
}

Expand Down
21 changes: 11 additions & 10 deletions tests/Feature/CalculationsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ function () {
}
);

it('calculate "count" on id field', function (string $component, object $params) {
it('calculates "count" on id field', function (string $component, object $params) {
livewire($component)
->call($params->theme)
->assertSee('Count ID: 12')
->set('search', 'Dish C')
->assertSee('Count ID: 1');
})->with('calculations');

it('calculate "sum" on price field', function (string $component, object $params) {
it('calculates "sum" on price field', function (string $component, object $params) {
livewire($component)
->call($params->theme)
->assertSeeHtml('<span>Sum Price: $15,000.60</span>')
Expand All @@ -29,29 +29,30 @@ function () {
->assertSeeHtml('<span>Sum Price: $600.00</span>');
})->with('calculations')->skip('Refactoring');

it('calculate "count" on price field', function (string $component, object $params) {
it('calculates "count" and formats on price field', function (string $component, object $params) {
livewire($component)
->call($params->theme)
->assertSeeHtml('Count Price: 12')
->assertSeeHtml('Count Price: 12 item(s)')
->set('search', 'Dish C')
->assertSeeHtml('Count Price: 1')
->assertSeeHtml('Count Price: 1 item(s)')
->set('search', 'Dish F')
->assertSeeHtml('Count Price: 1');
->assertSeeHtml('Count Price: 1 item(s)');
})->with('calculations');

it('calculate "avg" on price field', function (string $component, object $params) {
it('calculates and formats "avg" on price field and calorie fields', function (string $component, object $params) {
livewire($component)
->call($params->theme)
->assertSeeHtml('<span>Avg Price: $1,250.05</span>');
->assertSeeHtml('<span>Avg Price: $1,250.05</span>')
->assertSeeHtml('<span>Average: 224 kcal</span>');
})->with('calculations');

it('calculate "min" on price field', function (string $component, object $params) {
it('calculates "min" on price field', function (string $component, object $params) {
livewire($component)
->call($params->theme)
->assertSeeHtml('<span>Min Price: $100.00</span>');
})->with('calculations');

it('calculate "max" on price field', function (string $component, object $params) {
it('calculates "max" on price field', function (string $component, object $params) {
livewire($component)
->call($params->theme)
->assertSeeHtml('<span>Max Price: $7,500.00</span>');
Expand Down

0 comments on commit c855c70

Please sign in to comment.