Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Collections Laravel Package

cartalyst/collections

Cartalyst Collections extends Laravel's Collection with a richer set of array helpers, macros, and utilities for filtering, transforming, and manipulating data. It offers convenient methods for everyday PHP workflows, making complex array operations cleaner and more expressive while staying familiar...

View on GitHub
Deep Wiki
Context7

Getting Started

Verify what you have before you install anything. cartalyst/collections is a single Collection class wrapping a PHP array with fluent map/filter/sort helpers plus ArrayAccess, Countable, and IteratorAggregate. It is framework-agnostic, BSD-3-Clause, and last saw a substantive release in 2015. On Laravel you already own Illuminate\Support\Collection and Arr. Day-to-day, the only realistic reason to touch this is that it arrived transitively in a Sentinel/Platform-lineage app and you are containing or removing it.

If you must add it, pin the exact version.

composer require cartalyst/collections:1.0.0   # exact, not ^1.0

A caret range on a package with no cadence and no named maintainer means the next tag silently changes your runtime.

Read in this order:

  1. composer.json — the PHP constraint. This single line tells you whether the package even acknowledges PHP 8.
  2. src/Collection.php — the entire API surface. It is small; read it end to end so you know the actual method names and return types, not the README's summary.
  3. tests/ — your de facto spec for ordering, key preservation, and serialization shape.
  4. The v1.0.0 diff — confirm it is housekeeping, not a signature change to something you call.

First use case — wrap at the boundary, unwrap before you leave it. The realistic day-one scenario is legacy code that receives an associative array (decoded JSON, a Sentinel payload) and wants to transform it without a nest of foreach loops:

use Cartalyst\Collections\Collection;

$active = (new Collection($payload['users']))
    ->filter(fn ($user) => $user['active'] === true)
    ->map(fn ($user) => ['id' => $user['id'], 'email' => $user['email']])
    ->toArray();

Run the five-minute spike before you commit to it. One test file against your actual PHP and framework target, covering: chaining two methods, key preservation through filter, count() vs ->count(), foreach iteration, json_encode($collection), and a toArray() round-trip. Any surprise here is worth more than an hour of README reading, and you learn it before the code is load-bearing.

Decision rule to write down now: new code uses collect(); existing code touching Cartalyst\Collections\Collection gets wrapped behind an internal interface and scheduled for migration. This package is a containment target, not a tool.

Implementation Patterns

Boundary wrapping. Keep the collection as a local variable inside one method, never as a type that crosses a layer. Convert on entry (new Collection($array)), work, convert on exit (->toArray()). No controller returns one, no repository accepts one, no model holds one. That constraint turns future migration into a find-and-replace instead of archaeology.

Containment adapter — the pattern you should actually adopt. If you have more than a handful of call sites, spend a fraction of the migration budget on a seam rather than the whole rewrite:

namespace App\Support;

interface UserList
{
    /** @return array<int, array{id:int,email:string}> */
    public function activeContacts(array $users): array;
}

Implement it today with the Cartalyst class, tomorrow with collect(). Call sites depend on UserList; the package name appears in exactly one file. This also lets you parallel-run both implementations, compare in a test, and flip the binding.

Pure chained pipelines. The fluent API is at its best when the chain is side-effect free — filter, map, pluck, sort, toArray(). Keep I/O ($this->mailer->send(...)) out of the chain and iterate the result afterwards. Partly good practice, partly defensive: without a documented mutability contract, you do not want to reason about whether a mid-chain call returned $this or a new instance while also doing work.

Iteration interop. Because it implements IteratorAggregate and Countable, it drops into existing code without ceremony:

foreach ($collection as $key => $item) { /* ... */ }

if (count($collection) > 0) { /* ... */ }

$collection['user_42'];            // ArrayAccess
isset($collection['user_42']);     // see gotchas

This is the package's genuine strength for legacy code: it is array-shaped enough that old foreach-heavy methods accept it with minimal edits.

JSON output. json_encode($collection) works via JsonSerializable/public-array conversion; the package may also expose toJson(). In an API controller prefer the explicit form — response()->json($collection->toArray()) — so the wire format is a plain array you can assert on, not an artifact of the class's serialization internals.

Contract tests before migration. Whatever semantics you actually depend on — key preservation through filter, sort stability, whether map reindexes or preserves keys — capture them as a small suite first. Those tests are the acceptance criteria for the replacement and the only thing standing between you and a silent ordering change in a production report.

Static analysis and IDE support. The class predates generics and modern docblocks. Add a stub or @method/@return docblock file if you run PHPStan or Psalm — or exclude the vendor path and let your own adapter carry the types. Otherwise every ->map() returns mixed and the type safety you pay for elsewhere quietly evaporates at the boundary.

Migration sequencing. Inventory usages into three buckets: direct collect() equivalents, genuinely unique behavior, and dead code. Dead code goes first (free win), direct equivalents next, one at a time, with the contract tests green. Unique behavior last — reimplement in a small owned class rather than forking, unless the behavior is genuinely intricate. Delete the adapter only after a full release cycle of clean parity.

Gotchas and Tips

Mutability is the first thing to verify. Older collection libraries often mutate in place and return $this for chaining. If that is the case here, $original and $filtered are the same object and any "I kept the original around" assumption is wrong. Test it:

$original = new Collection([3, 1, 2]);
$sorted = $original->sort();
// is $original === $sorted ? is $original still [3,1,2] ?

If methods mutate, clone before any branch and treat every chain as destructive.

isset() is not array_key_exists(). ArrayAccess::offsetExists is very commonly implemented with isset($this->items[$key]), which returns false for keys whose value is null. If your payload distinguishes "absent" from "null", you will be silently wrong. Test a null value explicitly, and use ->has() / ->get() if the package provides them rather than bracket-plus-isset.

Key preservation is not guaranteed to be uniform. filter may or may not preserve keys; map may or may not reindex; sort almost certainly does not. If anything downstream json_encodes the result, key preservation flips your payload from [...] to {...} — a breaking API change no type checker will catch. Assert the exact output shape in a test.

Don't assume Laravel ergonomics. No Collection::macro(), no higher-order proxies (->map->name), no LazyCollection for large payloads, no Arr interop, no when()/tap(), no dd(). Method names also differ from Laravel's (add/put/forget vs push/set/forget), which makes copy-pasted Laravel snippets a reliable source of BadMethodCallException. Keep the source file open the first week.

PHP 8 is unproven until you run it. Watch for dynamic properties, implicit nullable parameter types, ${var} string interpolation, each(), and PHP 4-style constructors. Run your spike on the actual target version, not your local one, and check the deprecation log at E_ALL — these fail quietly today and loudly after the next framework bump.

Composer constraint conflicts look like dependency problems. If something in your tree requires cartalyst/collections ^0.x and you pinned 1.0.0, you get a resolution conflict that is really a tag-reset problem. composer why cartalyst/collections first, always. Never add a branch alias or a dev-master constraint to work around it — that trades a visible conflict for an invisible one.

No security patch path. There is no SECURITY.md and no named maintainer. That is not cause for panic about the code you have; it is a reason to have a documented answer to "who fixes this when it breaks?" If the answer is "we vendor it," vendor it properly — commit it, own it, add it to the SBOM exception list with an exit date. If the answer is "nobody," schedule the removal.

Debugging. There are no debug helpers. var_dump($collection->toArray()) and exit is the whole toolkit, so lean on Xdebug and step through the chain rather than trying to print from inside a fluent pipeline. When a chain misbehaves, break it into named intermediate variables — you will find the offending step in seconds instead of guessing which of six chained calls dropped the key.

Extension points exist but you own the consequences. Subclassing or forking is trivial for a single-class package. Do it only if you have behavior you genuinely cannot reproduce in 40 lines, and when you do: namespace it under your own vendor prefix, add tests, and record it in an ADR. A forked single-class utility nobody owns is strictly worse than the abandoned original — now the abandonment is your fault and the exit plan is gone.

The best day-to-day leverage is the exit. Every hour spent on an adapter and a contract test set converts a dead dependency from a runtime risk into a one-line binding swap. That is the ROI here — not the fluent API, which the framework already gives you.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle