Skip to content

Commit 3f12bc7

Browse files
committed
columnAt, groupBy: skip scalar rows in mixed data like indexBy does
Mixed data (some rows, some scalars) passes assertNestedArray(), which only requires one nested value. columnAt() then threw a TypeError from count() on the scalar, and groupBy() grouped scalars under the '' key. indexBy() already skips scalar rows; now all three agree. Tests pin the skip in both modes. Also in Deprecations.php docblocks: fold sprintf()'s asRaw() note into its example comment, and move offsetSet()'s note above the @deprecated tag.
1 parent 7b8054b commit 3f12bc7

3 files changed

Lines changed: 31 additions & 6 deletions

File tree

src/Deprecations.php

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -165,13 +165,12 @@ public function each(Closure $callback): static
165165
* $list->sprintf('<li>{value}</li>')->implode("\n");
166166
* $list->map(fn($v) => "<li>$v</li>")->implode("\n");
167167
*
168-
* // SmartArrayHtml (HTML-encoded), old and new:
168+
* // SmartArrayHtml (HTML-encoded), old and new. asRaw() matters here:
169+
* // without it, implode() returns a SmartString that would re-encode
170+
* // the HTML tags at output.
169171
* $row->sprintf('<td>{value}</td>')->implode("\n");
170172
* $row->asRaw()->map(fn($v) => "<td>" . htmlspecialchars((string)$v) . "</td>")->implode("\n"); // or h() in CMS Builder
171173
*
172-
* The asRaw() in the HTML-mode replacement matters: without it, implode()
173-
* returns a SmartString that would re-encode the HTML tags at output.
174-
*
175174
* @param string $format sprintf format string (supports {value}/{key} aliases)
176175
* @return SmartArray Pre-formatted strings that won't be re-encoded on output
177176
* @throws InvalidArgumentException If called on a nested array
@@ -404,11 +403,10 @@ public function chunk(int $size): static
404403
/**
405404
* Sets a value in the SmartArray using array syntax.
406405
*
407-
* @deprecated Use ->key = $value or ->{'key'} = $value instead of $array['key'] = $value
408-
*
409406
* Note: If you add a key after the array is created the position properties will not be updated.
410407
* If needed you can recreate the array like this: $newArray = SmartArray::new($oldArray->toArray());
411408
*
409+
* @deprecated Use ->key = $value or ->{'key'} = $value instead of $array['key'] = $value
412410
* @param mixed $offset The key to set. If null, the value is appended to the array.
413411
* @param mixed $value The value to set. Will be converted to SmartString or SmartArray as appropriate.
414412
*

src/SmartArrayBase.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,9 @@ public function groupBy(string $field): static
724724

725725
$values = [];
726726
foreach ($this->toArray() as $row) {
727+
if (!is_array($row)) {
728+
continue; // scalar rows have no fields to group by
729+
}
727730
$key = $row[$field] ?? null;
728731
$values[$key][] = $row;
729732
}
@@ -755,6 +758,9 @@ public function columnAt(int $index): static
755758

756759
$values = [];
757760
foreach ($this->toArray() as $row) {
761+
if (!is_array($row)) {
762+
continue; // scalar rows have no columns to extract
763+
}
758764
$count = count($row);
759765
$rowIndex = ($index < 0) ? $count + $index : $index; // Convert negative indexes to positive
760766

tests/Unit/ProjectionTest.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,15 @@ public function testPluckNthOnFlatThrows(string $class): void
118118
$class::new(['a', 'b'])->pluckNth(0);
119119
}
120120

121+
#[DataProvider('modeProvider')]
122+
public function testColumnAtSkipsScalarRows(string $class): void
123+
{
124+
// One array value makes the array "nested"; scalar rows have no columns to extract
125+
$sa = $class::new([['a', 'b'], 'scalar', ['c', 'd']]);
126+
127+
$this->assertSame(['a', 'c'], $sa->columnAt(0)->toArray());
128+
}
129+
121130
//endregion
122131
//region column()
123132

@@ -280,6 +289,18 @@ public function testGroupByOnFlatThrows(string $class): void
280289
$class::new(['a', 'b'])->groupBy('g');
281290
}
282291

292+
#[DataProvider('modeProvider')]
293+
public function testGroupBySkipsScalarRows(string $class): void
294+
{
295+
// One array value makes the array "nested"; scalar rows have no fields to group by
296+
$sa = $class::new([['g' => 'a', 'v' => 1], 'scalar', ['g' => 'a', 'v' => 2]]);
297+
298+
[$result, $output] = $this->captureOutput(fn() => $sa->groupBy('g'));
299+
300+
$this->assertSame(['a' => [['g' => 'a', 'v' => 1], ['g' => 'a', 'v' => 2]]], $result->toArray());
301+
$this->assertSame('', $output);
302+
}
303+
283304
//endregion
284305
//region keys() / values()
285306

0 commit comments

Comments
 (0)