Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
a07d272
Complete console command typing and preserve supported inputs
binaryfire Sep 11, 2026
845d360
Complete array type coverage and correct sorting contracts
binaryfire Sep 11, 2026
d25b195
Complete model appended-attribute test coverage
binaryfire Sep 11, 2026
7a931bb
Use the default when clamped input is not numeric
binaryfire Sep 11, 2026
baea152
Complete collection contracts, fixtures and adjacent grouping
binaryfire Sep 11, 2026
6113204
Remove unsupported SQL Server schema paths and restore generated-colu…
binaryfire Sep 11, 2026
329d747
Complete file validation custom-message test typing
binaryfire Sep 11, 2026
035fd9f
Align mailable assertion fixtures with upstream order
binaryfire Sep 11, 2026
bf9e807
Stop migration commands when a child operation fails
binaryfire Sep 11, 2026
641040b
Handle maintenance deactivation between cache reads
binaryfire Sep 11, 2026
12179e5
Complete maintenance cookie validation and usage documentation
binaryfire Sep 11, 2026
95e732a
Use consistent command exit-code constants
binaryfire Sep 11, 2026
777a200
Complete lazy Eloquent creation values and fix through-relation colli…
binaryfire Sep 11, 2026
0e40ed9
Allow fluent string deduplication of multiple characters
binaryfire Sep 11, 2026
4f1ace1
Complete notification hook coverage and fixture contracts
binaryfire Sep 11, 2026
cfdc5a7
Complete batch cancellation event documentation and test types
binaryfire Sep 11, 2026
a356387
Handle maintenance file removal during worker refreshes
binaryfire Sep 11, 2026
df9a48d
Propagate maintenance file read failures through HTTP middleware
binaryfire Sep 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/bus/src/Events/BatchCanceled.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ class BatchCanceled
{
/**
* Create a new event instance.
*
* @param null|Throwable $exception the exception that caused the cancellation
*/
public function __construct(
public Batch $batch,
Expand Down
2 changes: 1 addition & 1 deletion src/cache/src/Console/CacheTableCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public function handle(): int

$this->components->info('Migrations created successfully.');

return 0;
return self::SUCCESS;
}

/**
Expand Down
6 changes: 3 additions & 3 deletions src/cache/src/Console/PruneDbExpiredCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class PruneDbExpiredCommand extends Command
/**
* Execute the console command.
*/
public function handle(): ?int
public function handle(): int
{
$store = $this->argument('store');
$cache = $this->hypervel->make('cache')->store($store);
Expand All @@ -42,14 +42,14 @@ public function handle(): ?int
$this->error("The cache store [{$store}] is not using the database driver.");
}

return 1;
return self::FAILURE;
}

$deleted = $cache->getStore()->pruneExpired();

$this->info("Successfully pruned {$deleted} expired cache entries.");

return 0;
return self::SUCCESS;
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/cache/src/Console/PruneStaleTagsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public function handle(): int
if (! method_exists($store, 'flushStaleTags')) {
$this->components->info('The selected cache store does not support pruning stale tags.');

return 0;
return self::SUCCESS;
}

$stats = $store->flushStaleTags();
Expand All @@ -54,7 +54,7 @@ public function handle(): int

$this->components->info('Stale cache tags pruned successfully.');

return 0;
return self::SUCCESS;
}

/**
Expand Down
23 changes: 12 additions & 11 deletions src/collections/src/Arr.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public static function collapse(iterable $array): array
$results = [];

foreach ($array as $values) {
if ($values instanceof Collection) {
if ($values instanceof Enumerable) {
$results[] = $values->all();
} elseif (is_array($values)) {
$results[] = $values;
Expand Down Expand Up @@ -364,7 +364,7 @@ public static function flatten(iterable $array, float $depth = INF): array
$result = [];

foreach ($array as $item) {
$item = $item instanceof Collection ? $item->all() : $item;
$item = $item instanceof Enumerable ? $item->all() : $item;

if (! is_array($item)) {
$result[] = $item;
Expand Down Expand Up @@ -687,6 +687,11 @@ public static function keyBy(iterable $array, callable|array|string $keyBy): arr

/**
* Prepend the key names of an associative array.
*
* @template TValue
*
* @param array<TValue> $array

@cubic-dev-ai cubic-dev-ai Bot Sep 11, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: array<TValue> narrows this associative-array API to integer-keyed inputs in static analysis, rejecting valid calls such as ['id' => '123']. Declare the parameter with array<array-key, TValue> so string and integer keys remain supported.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/collections/src/Arr.php, line 693:

<comment>`array<TValue>` narrows this associative-array API to integer-keyed inputs in static analysis, rejecting valid calls such as `['id' => '123']`. Declare the parameter with `array<array-key, TValue>` so string and integer keys remain supported.</comment>

<file context>
@@ -687,6 +687,11 @@ public static function keyBy(iterable $array, callable|array|string $keyBy): arr
+     *
+     * @template TValue
+     *
+     * @param array<TValue> $array
+     * @return array<array-key, TValue>
      */
</file context>
Suggested change
* @param array<TValue> $array
* @param array<array-key, TValue> $array
Fix with cubic

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping the existing annotation. PHPStan's array<TValue> accepts string and integer keys; it does not imply array<int, TValue>. A max-level check of Arr::prependKeysWith(['id' => '123'], 'user_') passes and preserves the value type. Spelling out the key type would not fix an error.

* @return array<array-key, TValue>
*/
public static function prependKeysWith(array $array, string $prependWith): array
{
Expand Down Expand Up @@ -834,11 +839,9 @@ public static function mapWithKeys(array $array, callable $callback): array
* Run a map over each nested chunk of items.
*
* @template TKey
* @template TValue
*
* @param array<TKey, array> $array
* @param callable(mixed...): TValue $callback
* @return array<TKey, TValue>
* @return array<TKey, mixed>
*/
public static function mapSpread(array $array, callable $callback): array
{
Expand Down Expand Up @@ -1024,7 +1027,7 @@ public static function sole(array $array, ?callable $callback = null): mixed
* @template TValue
*
* @param iterable<TKey, TValue> $array
* @param null|array<int, (0|1|callable(TValue, TValue): -1)|array{string, 'asc'|'desc'|SortDirection}>|callable|int|string $callback
* @param null|array<array-key, array{int|string, 'asc'|'desc'|bool|SortDirection}|(callable(TValue, TValue): mixed)|int|string>|(callable(TValue, TKey): mixed)|int|string $callback
* @return array<TKey, TValue>
*/
public static function sort(iterable $array, callable|array|int|string|null $callback = null): array
Expand All @@ -1045,7 +1048,7 @@ public static function sort(iterable $array, callable|array|int|string|null $cal
* @template TValue
*
* @param iterable<TKey, TValue> $array
* @param null|array<int, (0|1|callable(TValue, TValue): -1)|array{string, 'asc'|'desc'|SortDirection}>|callable|int|string $callback
* @param null|array<array-key, array{int|string, 'asc'|'desc'|bool|SortDirection}|(callable(TValue, TValue): mixed)|int|string>|(callable(TValue, TKey): mixed)|int|string $callback
* @return array<TKey, TValue>
*/
public static function sortDesc(iterable $array, callable|array|int|string|null $callback = null): array
Expand Down Expand Up @@ -1128,8 +1131,7 @@ public static function string(ArrayAccess|array $array, string|int|null $key, ?s
/**
* Conditionally compile classes from an array into a CSS class list.
*
* @param array<int, int|string>|array<string, bool>|string $array
* @return ($array is array<string, false> ? '' : ($array is '' ? '' : ($array is array{} ? '' : non-empty-string)))
* @param array<array-key, mixed>|string $array
*/
public static function toCssClasses(array|string $array): string
{
Expand All @@ -1151,8 +1153,7 @@ public static function toCssClasses(array|string $array): string
/**
* Conditionally compile styles from an array into a style list.
*
* @param array<int, int|string>|array<string, bool>|string $array
* @return ($array is array<string, false> ? '' : ($array is '' ? '' : ($array is array{} ? '' : non-empty-string)))
* @param array<array-key, mixed>|string $array
*/
public static function toCssStyles(array|string $array): string
{
Expand Down
29 changes: 15 additions & 14 deletions src/collections/src/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ public function collapseWithKeys(): static
$results = [];

foreach ($this->items as $key => $values) {
if ($values instanceof Collection) {
if ($values instanceof Enumerable) {
$values = $values->all();
} elseif (! is_array($values)) {
continue;
Expand Down Expand Up @@ -511,15 +511,17 @@ public function getOrPut(mixed $key, mixed $value): mixed
* @template TGroupKey of array-key|bool|null|UnitEnum|BaseStringable
*
* @param array|(callable(TValue, TKey): (array<array-key, TGroupKey>|TGroupKey))|string $groupBy
* @return static<
* ($groupBy is (array|string)
* ? array-key
* : (TGroupKey is array-key ? TGroupKey : (TGroupKey is bool ? int : (TGroupKey is (BaseStringable|null) ? string : array-key)))),
* static<($preserveKeys is true ? TKey : int), ($groupBy is array ? mixed : TValue)>
* >
* @return ($groupBy is array
* ? Collection<array-key, Collection<array-key, mixed>>|static<array-key, Collection<array-key, mixed>>
* : static<
* ($groupBy is string
* ? array-key
* : (TGroupKey is array-key ? TGroupKey : (TGroupKey is bool ? int : (TGroupKey is (BaseStringable|null) ? string : array-key)))),
* static<($preserveKeys is true ? TKey : int), TValue>
* >)
*/
#[Override]
public function groupBy(callable|array|string $groupBy, bool $preserveKeys = false): static
public function groupBy(callable|array|string $groupBy, bool $preserveKeys = false): Collection|static
{
if (! $this->useAsCallable($groupBy) && is_array($groupBy)) {
$nextGroups = $groupBy;
Expand Down Expand Up @@ -558,7 +560,6 @@ public function groupBy(callable|array|string $groupBy, bool $preserveKeys = fal
$result = $this->newInstance($results);

if (! empty($nextGroups)) {
// @phpstan-ignore return.type (recursive groupBy returns Enumerable, PHPStan can't verify it matches static)
return $result->map->groupBy($nextGroups, $preserveKeys);
}

Expand Down Expand Up @@ -1244,11 +1245,11 @@ public function shuffle(): static
*
* @param positive-int $size
* @param positive-int $step
* @return static<int, static>
* @return Collection<int, static>|static<int, static>
*
* @throws InvalidArgumentException
*/
public function sliding(int $size = 2, int $step = 1): static
public function sliding(int $size = 2, int $step = 1): Collection|static
{
if ($size < 1) {
throw new InvalidArgumentException('Size value must be at least 1.');
Expand Down Expand Up @@ -1508,7 +1509,7 @@ public function sortDesc(int $options = SORT_REGULAR): static
/**
* Sort the collection using the given callback.
*
* @param array<array-key, array{int|string, 'asc'|'desc'|SortDirection}|(callable(TValue, TKey): mixed)|(callable(TValue, TValue): mixed)|int|string>|(callable(TValue, TKey): mixed)|int|string $callback
* @param array<array-key, array{int|string, 'asc'|'desc'|bool|SortDirection}|(callable(TValue, TValue): mixed)|int|string>|(callable(TValue, TKey): mixed)|int|string $callback
*/
public function sortBy(callable|array|int|string $callback, int $options = SORT_REGULAR, SortDirection|bool $descending = false): static
{
Expand Down Expand Up @@ -1545,7 +1546,7 @@ public function sortBy(callable|array|int|string $callback, int $options = SORT_
/**
* Sort the collection using multiple comparisons.
*
* @param array<array-key, array{int|string, 'asc'|'desc'|SortDirection}|(callable(TValue, TKey): mixed)|(callable(TValue, TValue): mixed)|int|string> $comparisons
* @param array<array-key, array{int|string, 'asc'|'desc'|bool|SortDirection}|(callable(TValue, TValue): mixed)|int|string> $comparisons
*/
protected function sortByMany(array $comparisons = [], int $options = SORT_REGULAR): static
{
Expand Down Expand Up @@ -1603,7 +1604,7 @@ protected function sortByMany(array $comparisons = [], int $options = SORT_REGUL
/**
* Sort the collection in descending order using the given callback.
*
* @param array<array-key, array{int|string, 'asc'|'desc'|SortDirection}|(callable(TValue, TKey): mixed)|(callable(TValue, TValue): mixed)|int|string>|(callable(TValue, TKey): mixed)|int|string $callback
* @param array<array-key, array{int|string, 'asc'|'desc'|bool|SortDirection}|(callable(TValue, TValue): mixed)|int|string>|(callable(TValue, TKey): mixed)|int|string $callback
*/
public function sortByDesc(callable|array|int|string $callback, int $options = SORT_REGULAR): static
{
Expand Down
48 changes: 30 additions & 18 deletions src/collections/src/Enumerable.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ public static function make(Arrayable|iterable|null $items = []): static;
* @template TTimesValue
*
* @param null|(callable(int): TTimesValue) $callback
* @return ($callback is null ? static<int, int> : static<int, TTimesValue>)
* @return ($callback is null ? static<int, int> : Collection<int, TTimesValue>|static<int, TTimesValue>)
*/
public static function times(int $number, ?callable $callback = null): static;
public static function times(int $number, ?callable $callback = null): Collection|static;

/**
* Create a collection with the given range.
Expand Down Expand Up @@ -440,14 +440,16 @@ public function get(mixed $key, mixed $default = null): mixed;
* @template TGroupKey of array-key|bool|null|UnitEnum|BaseStringable
*
* @param array|(callable(TValue, TKey): (array<array-key, TGroupKey>|TGroupKey))|string $groupBy
* @return static<
* ($groupBy is (array|string)
* ? array-key
* : (TGroupKey is array-key ? TGroupKey : (TGroupKey is bool ? int : (TGroupKey is (BaseStringable|null) ? string : array-key)))),
* Collection<($preserveKeys is true ? TKey : int), ($groupBy is array ? mixed : TValue)>
* >
* @return ($groupBy is array
* ? Collection<array-key, Collection<array-key, mixed>>|static<array-key, Collection<array-key, mixed>>
* : static<
* ($groupBy is string
* ? array-key
* : (TGroupKey is array-key ? TGroupKey : (TGroupKey is bool ? int : (TGroupKey is (BaseStringable|null) ? string : array-key)))),
* Collection<($preserveKeys is true ? TKey : int), TValue>
* >)
*/
public function groupBy(callable|array|string $groupBy, bool $preserveKeys = false): static;
public function groupBy(callable|array|string $groupBy, bool $preserveKeys = false): Collection|static;

/**
* Key an associative array by a field or using a callback.
Expand Down Expand Up @@ -576,8 +578,10 @@ public function map(callable $callback): Collection|static;

/**
* Run a map over each nested chunk of items.
*
* @return Collection<TKey, mixed>|static<TKey, mixed>
*/
public function mapSpread(callable $callback): static;
public function mapSpread(callable $callback): Collection|static;

/**
* Run a dictionary map over the items.
Expand All @@ -601,9 +605,9 @@ public function mapToDictionary(callable $callback): static;
* @template TMapToGroupsValue
*
* @param callable(TValue, TKey): array<TMapToGroupsKey, TMapToGroupsValue> $callback
* @return static<TMapToGroupsKey, static<int, TMapToGroupsValue>>
* @return Collection<TMapToGroupsKey, static<int, TMapToGroupsValue>>|static<TMapToGroupsKey, static<int, TMapToGroupsValue>>
*/
public function mapToGroups(callable $callback): static;
public function mapToGroups(callable $callback): Collection|static;

/**
* Run an associative map over each of the items.
Expand All @@ -624,7 +628,7 @@ public function mapWithKeys(callable $callback): Collection|static;
* @template TFlatMapKey of array-key
* @template TFlatMapValue
*
* @param callable(TValue, TKey): (array<TFlatMapKey, TFlatMapValue>|Collection<TFlatMapKey, TFlatMapValue>) $callback
* @param callable(TValue, TKey): (array<TFlatMapKey, TFlatMapValue>|Enumerable<TFlatMapKey, TFlatMapValue>) $callback
* @return static<TFlatMapKey, TFlatMapValue>
*/
public function flatMap(callable $callback): Collection|static;
Expand Down Expand Up @@ -823,9 +827,9 @@ public function shuffle(): static;
/**
* Create chunks representing a "sliding window" view of the items in the collection.
*
* @return static<int, static>
* @return Collection<int, static>|static<int, static>
*/
public function sliding(int $size = 2, int $step = 1): static;
public function sliding(int $size = 2, int $step = 1): Collection|static;

/**
* Skip the first {$count} items.
Expand Down Expand Up @@ -894,6 +898,14 @@ public function chunk(int $size): static;
*/
public function chunkWhile(callable $callback): static;

/**
* Chunk the collection into chunks by comparing adjacent values using the given key or callback.
*
* @param (callable(TValue, TKey): mixed)|string $key
* @return static<int, static<TKey, TValue>>
*/
public function chunkBy(callable|string $key): static;

/**
* Split a collection into a certain number of groups, and fill the first groups completely.
*
Expand All @@ -918,15 +930,15 @@ public function sortDesc(int $options = SORT_REGULAR): static;
/**
* Sort the collection using the given callback.
*
* @param array<array-key, array{int|string, 'asc'|'desc'|SortDirection}|(callable(TValue, TKey): mixed)|(callable(TValue, TValue): mixed)|int|string>|(callable(TValue, TKey): mixed)|int|string $callback
* @param array<array-key, array{int|string, 'asc'|'desc'|bool|SortDirection}|(callable(TValue, TValue): mixed)|int|string>|(callable(TValue, TKey): mixed)|int|string $callback
* @param int-mask-of<SORT_FLAG_CASE|SORT_LOCALE_STRING|SORT_NATURAL|SORT_NUMERIC|SORT_REGULAR|SORT_STRING> $options
*/
public function sortBy(array|callable|int|string $callback, int $options = SORT_REGULAR, SortDirection|bool $descending = false): static;

/**
* Sort the collection in descending order using the given callback.
*
* @param array<array-key, array{int|string, 'asc'|'desc'|SortDirection}|(callable(TValue, TKey): mixed)|(callable(TValue, TValue): mixed)|int|string>|(callable(TValue, TKey): mixed)|int|string $callback
* @param array<array-key, array{int|string, 'asc'|'desc'|bool|SortDirection}|(callable(TValue, TValue): mixed)|int|string>|(callable(TValue, TKey): mixed)|int|string $callback
* @param int-mask-of<SORT_FLAG_CASE|SORT_LOCALE_STRING|SORT_NATURAL|SORT_NUMERIC|SORT_REGULAR|SORT_STRING> $options
*/
public function sortByDesc(array|callable|int|string $callback, int $options = SORT_REGULAR): static;
Expand Down Expand Up @@ -984,7 +996,7 @@ public function takeWhile(mixed $value): static;
/**
* Pass the collection to the given callback and then return it.
*
* @param callable(TValue): mixed $callback
* @param callable($this): mixed $callback
*/
public function tap(callable $callback): static;

Expand Down
10 changes: 5 additions & 5 deletions src/collections/src/HigherOrderCollectionProxy.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@
namespace Hypervel\Support;

/**
* @template TKey of array-key
* @template TMethod of string
* @template TValue
* @template TCollection of Enumerable<array-key, TValue>
*
* @template-covariant TValue
*
* @mixin \Hypervel\Support\Enumerable<TKey, TValue>
* @mixin TValue
*/
class HigherOrderCollectionProxy
{
/**
* Create a new proxy instance.
*
* @param \Hypervel\Support\Enumerable<TKey, TValue> $collection
* @param TCollection $collection
* @param TMethod $method
*/
public function __construct(
protected Enumerable $collection,
Expand Down
Loading