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

Collection Laravel Package

small/collection

A lightweight collection package for PHP and Laravel that wraps arrays in a fluent, chainable API for filtering, mapping, grouping, sorting, and reducing data. Small and dependency-free, it keeps dataset manipulation readable and expressive.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and inspect before you build:

composer require small/collection

Because this package has no stars, no dependents, and no published API docs beyond the description, your first hour should be spent reading source rather than reading docs:

  1. Open composer.json and check the PSR-4 namespace and the PHP version constraint — that tells you whether it will drop into an existing Laravel app or needs a polyfill.
  2. Read src/ in this order: the base collection class, then the selector/query class, then any exception classes.
  3. Run the package's own test suite (vendor/bin/phpunit or whatever scripts defines). If it has no tests, treat that as a signal to write a thin internal wrapper instead of using it directly across your codebase.

First use case — filter a hydrated result set without touching the database:

use Small\Collection\Collection;
use Small\Collection\Selector;

$users = new Collection($repository->allActive());

$admins = $users->select(
    Selector::where('role', 'admin')
        ->andWhere('lastLoginAt', '>', new DateTimeImmutable('-30 days'))
);

foreach ($admins as $user) {
    // ...
}

The mental model to adopt on day one: Collection is the container, Selector is the query object. The selector is the valuable half of this package — it lets you express a multi-condition filter as a reusable, testable value object instead of a chain of closures buried in a controller. Start by extracting one hairy array_filter block from your codebase into a named selector and see whether the API fits. That single experiment will tell you more than any README.

If the API differs from the sketch above, look for the method that accepts a predicate and the class that builds predicates; those two are the package.

Implementation Patterns

Reusable named selectors. The biggest win is turning ad-hoc filtering into first-class domain objects. Build them once, test them in isolation, and pass them around:

final class OverdueInvoiceSelector
{
    public static function make(): Selector
    {
        return Selector::where('status', 'unpaid')
            ->andWhere('dueAt', '<', new DateTimeImmutable());
    }
}

This is also your insurance policy: if the package is abandoned, the blast radius is limited to the handful of places that reference Selector.

Repository boundary pattern. Wrap the package inside your repositories so the rest of the app never sees Small\Collection types directly. Return the collection from the repository, but expose a narrow interface — filter(Selector $s), map(callable $fn), toArray() — so you can swap in Laravel's Illuminate\Support\Collection or Doctrine's ArrayCollection later without a project-wide refactor.

final class InvoiceRepository
{
    public function overdue(OverdueInvoiceSelector $selector): Collection
    {
        return new Collection($this->model->all())->select($selector->make());
    }
}

Composition over long chains. Complex queries read better as a small set of composable selectors than as one 8-condition monolith. If the package supports combining selectors (->and(), ->or(), or a Composite class), use it aggressively. If it doesn't, compose at the array level and re-wrap.

Pipeline with map/filter/reduce. Collections are most useful when a selector narrows the candidate set and then a map reshapes it for the view or an export. Keep narrowing and reshaping as separate steps — mixing them makes both harder to test:

$rows = $invoices
    ->select($selector)
    ->map(fn ($invoice) => $exportRow->fromInvoice($invoice))
    ->toArray();

Custom selection logic belongs in your app, not the package. When you hit a condition the selector API can't express, resist the urge to fork the package. Write the predicate as a closure in your own code and pass it in — you'll keep upgrades cheap.

Testing. Selectors are pure functions over arrays, so they're ideal unit-test subjects: no database, no container, no mocking. Aim for one test per named selector covering the boundary cases (empty collection, all-match, none-match, null field values).

Gotchas and Tips

Verify the mutation model first. Many collection libraries are mutable — filter() may modify in place and return $this, or return a new instance. Both exist in the wild and the difference silently corrupts code that assumes the other. Write one throwaway script that calls a filter, then checks the original collection, before you write a single production line.

Watch for lost keys. If select() re-indexes (returns 0,1,2,…), code that relied on entity IDs as array keys will break quietly. If keys are preserved, toArray() will produce non-sequential arrays that json_encode turns into objects instead of arrays — a classic API response bug. Normalize with array_values() at the boundary.

Maturity risk is the headline caveat. Zero stars and zero dependents means: no Stack Overflow answers, no blog posts, no third-party bug reports. Before adopting, check the repository for (a) a licence file, (b) a recent commit, (c) CI config, and (d) a changelog. If two or more are missing, treat this as a piece of code you are adopting, not a dependency you are consuming — vendor it or pin it hard.

Pin the version and commit the lock file. For a package with no user base, ^1.0 can move under you. Use an exact constraint (1.0.3) in composer.json and review the diff before bumping. If you're on Laravel, composer outdated won't warn you meaningfully here.

Debugging predicates. When a selector returns fewer rows than expected, bisect it: build the selector condition by condition and log the count after each step. If the package exposes a toArray() of conditions or a __toString, dump that first — a wrong operator ('>' vs '>=') or a wrong date format is the usual culprit, especially with string-to-DateTime comparisons.

Type coercion with dates and money. Comparisons across mixed types ('2024-01-01' string vs DateTimeImmutable, or float vs formatted string) are where collection libraries most often surprise you. Normalize types as you hydrate the collection — do it in the repository, not in the selector.

Don't let it leak into Eloquent. Selecting in PHP is fine for in-memory sets of hundreds or low thousands. The moment you find yourself fetching Model::all() to filter it, you've built an N-row full table scan in application code. Rule of thumb: if the filtered result is smaller than ~10% of the table, the WHERE clause belongs in SQL.

Extension points to prefer. Look for interfaces or abstract classes you can implement (a SelectorInterface, a Comparator), and prefer those over subclassing concrete classes. Implementing an interface survives minor version upgrades; subclassing a concrete class usually doesn't.

Have an exit plan. Keep your wrapper thin and your selectors in app/ rather than vendor/. The realistic worst case here is that you replace this package in an afternoon — that only stays true if you never scattered Small\Collection\* type hints through your domain layer.

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.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
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