Skip to content

[12.x] Add containsAny() and containsAll() methods to Support Collection #56555

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

Ishoshot
Copy link

@Ishoshot Ishoshot commented Aug 5, 2025

This PR adds containsAny() and containsAll() methods to Laravel Collections, addressing a need for intuitive value-checking methods that complement the existing has()/hasAny() pattern.

Problem & Community Context

I was working on a feature today that required checking if a collection contains any of a given set. I was able to get it to work, but I felt there should be a better way, the Laravel way.

Moreover, A recent Twitter discussion highlighted the need for these methods when developers were implementing permission checking:

Original Tweet Context: A developer needed to check if a user's abilities collection contained any of multiple permissions ($ability or '*'), leading to the workaround: $user->role->abilities->flip()->hasAny($ability, '*')

SEE SCREENSHOTS

Twitter Thread: https://x.com/_newtonjob/status/1935593812698480961

This demonstrates a real-world use case where developers resort to unintuitive workarounds (flip()->hasAny()) because the obvious method names don't exist.

For containsAny():

// Current workarounds
collect($needles)->intersect($collection)->isNotEmpty()          // Unintuitive

$collection->contains(fn($item) => in_array($item, $needles))    // Hard to remember

collect($needles)->some(fn($needle) => $collection->contains($needle)) // Verbose

// With this PR
$collection->containsAny($needles)                               // Intuitive ✨

For containsAll():

// Current workarounds  
collect($needles)->every(fn($needle) => $collection->contains($needle)) // Verbose

collect($needles)->diff($collection)->isEmpty()                         // Unintuitive

$collection->intersect($needles)->count() === count($needles)           // Complex

// With this PR
$collection->containsAll($needles)                                       // Intuitive ✨

Testing

Both methods are thoroughly tested (92 assertions across 6 test methods) with the same rigor as existing Collection methods:

  • Simple values, callbacks, key-value pairs, operators
  • Empty collections, edge cases, type coercion
  • Both Collection and LazyCollection implementations

Screenshots

Screenshot 2025-08-05 at 22 22 50 Screenshot 2025-08-05 at 22 23 08

…Collection and LazyCollection classes- Add method signature to Enumerable interface- Support all contains() features: simple values, callbacks, key-value pairs, and operators- Add comprehensive test coverage for all usage patterns- Follow Laravel's existing patterns and conventions
- Add containsAll() method to Collection, LazyCollection, and Enumerable interface
- Returns true if ALL of the given values exist in the collection
- Supports all contains() features: simple values, callbacks, key-value pairs, and operators
- Add comprehensive test coverage (34 assertions across 2 test methods)
- Complements existing containsAny() method for complete coverage
- Follow Laravel's existing patterns and conventions
@shaedrich
Copy link
Contributor

shaedrich commented Aug 5, 2025

collect($needles)->some(fn($needle) => $collection->contains($needle)) // Verbose

You forgot about

collect($needles)->some($collection->contains(...)) // Significantly less verbose, innit?

not to mention

    /**
     * Determine if any of the given items exist in the collection.
     *
     * @param  mixed  $values
     * @return bool
     */
    public function containsAny($values)
    {
        if ($this->isEmpty()) {
            return false;
        }

        $values = is_array($values) ? $values : func_get_args();

        foreach ($values as $value) {
            if ($this->useAsCallable($value)) {
                $placeholder = new stdClass;

                if ($this->first($value, $placeholder) !== $placeholder) {
                    return true;
                }
            } elseif (is_array($value)) {
                if ($this->contains(...$value)) {
                    return true;
                }
            } elseif (in_array($value, $this->items)) {
                return true;
            }
        }

        return false;
    }

is ironically considerably verbose

@taylorotwell
Copy link
Member

Thanks for your pull request to Laravel!

Unfortunately, I'm going to delay merging this code for now. To preserve our ability to adequately maintain the framework, we need to be very careful regarding the amount of code we include.

If applicable, please consider releasing your code as a package so that the community can still take advantage of your contributions!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants