master

laravel/framework

Last updated at: 29/12/2023 09:25

Has.php

TLDR

The Has.php file is a trait that provides several methods related to asserting the presence of properties in objects. It contains methods for checking the count of properties, checking if properties exist, checking if all properties exist, checking if any property exists, and checking if properties are missing.

Methods

count

Asserts that a property is of the expected size. If $length parameter is not provided, it asserts the count of the entire object. If $length parameter is provided, it asserts the count of a specific property.

has

Ensures that the given property exists. It also has optional parameters for checking the count of the property and for executing a callback function.

hasAll

Asserts that all of the given properties exist.

hasAny

Asserts that at least one of the given properties exists.

missingAll

Asserts that none of the given properties exist.

missing

Asserts that a specific property does not exist.

Abstract Methods

dotPath

Compose the absolute "dot" path to the given key.

interactsWith

Marks the property as interacted.

prop

Retrieve a property within the current scope using "dot" notation.

scope

Instantiate a new "scope" at the path of the given key.

etc

Disables the interaction check.

first

Instantiate a new "scope" on the first element.

<?php

namespace Illuminate\Testing\Fluent\Concerns;

use Closure;
use Illuminate\Support\Arr;
use PHPUnit\Framework\Assert as PHPUnit;

trait Has
{
    /**
     * Assert that the prop is of the expected size.
     *
     * @param  string|int  $key
     * @param  int|null  $length
     * @return $this
     */
    public function count($key, int $length = null): self
    {
        if (is_null($length)) {
            $path = $this->dotPath();

            PHPUnit::assertCount(
                $key,
                $this->prop(),
                $path
                    ? sprintf('Property [%s] does not have the expected size.', $path)
                    : sprintf('Root level does not have the expected size.')
            );

            return $this;
        }

        PHPUnit::assertCount(
            $length,
            $this->prop($key),
            sprintf('Property [%s] does not have the expected size.', $this->dotPath($key))
        );

        return $this;
    }

    /**
     * Ensure that the given prop exists.
     *
     * @param  string|int  $key
     * @param  int|\Closure|null  $length
     * @param  \Closure|null  $callback
     * @return $this
     */
    public function has($key, $length = null, Closure $callback = null): self
    {
        $prop = $this->prop();

        if (is_int($key) && is_null($length)) {
            return $this->count($key);
        }

        PHPUnit::assertTrue(
            Arr::has($prop, $key),
            sprintf('Property [%s] does not exist.', $this->dotPath($key))
        );

        $this->interactsWith($key);

        if (! is_null($callback)) {
            return $this->has($key, function (self $scope) use ($length, $callback) {
                return $scope
                    ->tap(function (self $scope) use ($length) {
                        if (! is_null($length)) {
                            $scope->count($length);
                        }
                    })
                    ->first($callback)
                    ->etc();
            });
        }

        if (is_callable($length)) {
            return $this->scope($key, $length);
        }

        if (! is_null($length)) {
            return $this->count($key, $length);
        }

        return $this;
    }

    /**
     * Assert that all of the given props exist.
     *
     * @param  array|string  $key
     * @return $this
     */
    public function hasAll($key): self
    {
        $keys = is_array($key) ? $key : func_get_args();

        foreach ($keys as $prop => $count) {
            if (is_int($prop)) {
                $this->has($count);
            } else {
                $this->has($prop, $count);
            }
        }

        return $this;
    }

    /**
     * Assert that at least one of the given props exists.
     *
     * @param  array|string  $key
     * @return $this
     */
    public function hasAny($key): self
    {
        $keys = is_array($key) ? $key : func_get_args();

        PHPUnit::assertTrue(
            Arr::hasAny($this->prop(), $keys),
            sprintf('None of properties [%s] exist.', implode(', ', $keys))
        );

        foreach ($keys as $key) {
            $this->interactsWith($key);
        }

        return $this;
    }

    /**
     * Assert that none of the given props exist.
     *
     * @param  array|string  $key
     * @return $this
     */
    public function missingAll($key): self
    {
        $keys = is_array($key) ? $key : func_get_args();

        foreach ($keys as $prop) {
            $this->missing($prop);
        }

        return $this;
    }

    /**
     * Assert that the given prop does not exist.
     *
     * @param  string  $key
     * @return $this
     */
    public function missing(string $key): self
    {
        PHPUnit::assertNotTrue(
            Arr::has($this->prop(), $key),
            sprintf('Property [%s] was found while it was expected to be missing.', $this->dotPath($key))
        );

        return $this;
    }

    /**
     * Compose the absolute "dot" path to the given key.
     *
     * @param  string  $key
     * @return string
     */
    abstract protected function dotPath(string $key = ''): string;

    /**
     * Marks the property as interacted.
     *
     * @param  string  $key
     * @return void
     */
    abstract protected function interactsWith(string $key): void;

    /**
     * Retrieve a prop within the current scope using "dot" notation.
     *
     * @param  string|null  $key
     * @return mixed
     */
    abstract protected function prop(string $key = null);

    /**
     * Instantiate a new "scope" at the path of the given key.
     *
     * @param  string  $key
     * @param  \Closure  $callback
     * @return $this
     */
    abstract protected function scope(string $key, Closure $callback);

    /**
     * Disables the interaction check.
     *
     * @return $this
     */
    abstract public function etc();

    /**
     * Instantiate a new "scope" on the first element.
     *
     * @param  \Closure  $callback
     * @return $this
     */
    abstract public function first(Closure $callback);
}