deep-web-solutions/wordpress-framework-helpers

View on GitHub
src/includes/DataTypes/Arrays.php

Summary

Maintainability
A
35 mins
Test Coverage
<?php

namespace DeepWebSolutions\Framework\Helpers\DataTypes;

\defined( 'ABSPATH' ) || exit;

/**
 * A collection of very useful array manipulation helpers to be used throughout the projects.
 *
 * @since   1.0.0
 * @version 1.5.6
 * @author  Antonius Hegyes <a.hegyes@deep-web-solutions.com>
 * @package DeepWebSolutions\WP-Framework\Helpers\DataTypes
 */
final class Arrays {
    // region POLYFILLS

    /**
     * Checks whether a given array is a list or not. An array is considered a list if its keys consist of consecutive numbers from 0 to count($array)-1.
     *
     * @since   1.5.6
     * @version 1.5.6
     *
     * @see     https://www.php.net/manual/en/function.array-is-list.php#126574
     *
     * @param   array   $array  The array to check.
     *
     * @return  bool    True if the array is a list, false otherwise.
     */
    public static function is_list( array $array ): bool {
        if ( \PHP_VERSION_ID >= 80100 && \function_exists( '\array_is_list' ) ) {
            return \array_is_list( $array );
        }

        return array() === $array || ( \array_keys( $array ) === \range( 0, \count( $array ) - 1 ) );
    }

    // endregion

    /**
     * Returns a given variable if it is an array or a default value if not.
     *
     * @since   1.4.0
     * @version 1.4.0
     *
     * @param   mixed       $array      Variable to check.
     * @param   array|null  $default    The default value to return if check fails. By default, null.
     *
     * @return  array|null
     */
    public static function validate( $array, ?array $default = null ): ?array {
        return \is_array( $array ) ? $array : $default;
    }

    /**
     * Attempts to turn a variable of unknown type into an array.
     *
     * @since   1.4.0
     * @version 1.4.0
     *
     * @param   mixed       $array      Variable to cast.
     * @param   array|null  $default    The default value to return if all fails. By default, null.
     *
     * @return  array|null
     */
    public static function maybe_cast( $array, ?array $default = null ): ?array {
        if ( ! \is_null( self::validate( $array ) ) ) {
            return $array;
        }

        if ( ! \is_null( $array ) ) {
            return array( $array );
        }

        return $default;
    }

    /**
     * Attempts to cast a variable from an input stream into an array.
     *
     * @since   1.4.0
     * @version 1.4.0
     *
     * @param   int         $input_type     One of INPUT_GET, INPUT_POST, INPUT_COOKIE, INPUT_SERVER, or INPUT_ENV.
     * @param   string      $variable_name  Name of a variable to get.
     * @param   array|null  $default        The default value to return if all fails.
     *
     * @return  array|null
     */
    public static function maybe_cast_input( int $input_type, string $variable_name, ?array $default = null ): ?array {
        if ( \filter_has_var( $input_type, $variable_name ) ) {
            $array = \filter_input( $input_type, $variable_name, FILTER_UNSAFE_RAW, FILTER_FORCE_ARRAY );
            return self::maybe_cast( $array, $default );
        }

        return $default;
    }

    /**
     * Attempts to resolve a potential callable to an array value.
     *
     * @since   1.7.0
     * @version 1.7.0
     *
     * @param   mixed|callable  $array      Potential callable to resolve.
     * @param   array|null      $default    Default value to return on failure. By default, null.
     * @param   array           $args       Arguments to pass on to the callable. By default, none.
     *
     * @return  array|null
     */
    public static function resolve( $array, ?array $default = null, array $args = array() ): ?array {
        return self::maybe_cast( Callables::maybe_resolve( $array, $args ), $default );
    }

    /**
     * Validates an array of values against a safe-list. Returns a new array containing only valid entries.
     *
     * @since   1.4.0
     * @version 1.4.0
     *
     * @param   array       $entries    Array of entries to validate.
     * @param   array       $allowed    Array of allowed entries.
     * @param   mixed|null  $default    The value to replace invalid entries with.
     *
     * @return  array
     */
    public static function validate_allowed( array $entries, array $allowed, $default = null ): array {
        return \array_map(
            static function( $entry ) use ( $allowed, $default ) {
                $is_allowed = \in_array( $entry, $allowed, true );
                if ( false === $is_allowed && Strings::validate( $entry ) ) {
                    $entry      = \trim( $entry );
                    $is_allowed = \in_array( $entry, $allowed, true );
                }

                return $is_allowed ? $entry : $default;
            },
            $entries
        );
    }

    /**
     * Checks whether an array has any string keys or if they are all numerical.
     *
     * @since   1.0.0
     * @version 1.0.0
     *
     * @param   array   $array  The array to check.
     *
     * @return  bool    True if it has string keys, false otherwise.
     */
    public static function has_string_keys( array $array ): bool {
        return \count( \array_filter( \array_keys( $array ), '\is_string' ) ) > 0;
    }

    /**
     * Inserts new array entries after a given key within an existing array. If the key is not found,
     * appends entries at the end of the array.
     *
     * @since   1.0.0
     * @version 1.0.2
     * @see     https://gist.github.com/wpscholar/0deadce1bbfa4adb4e4c
     *
     * @param   array           $array          Associative array to insert the new entries into.
     * @param   string|int      $key            Key to insert the entries after.
     * @param   array           $new_entries    The new entries to insert.
     *
     * @return  array
     */
    public static function insert_after( array $array, $key, array $new_entries ): array {
        $index    = \array_search( $key, \array_keys( $array ), true );
        $position = ( false === $index ) ? \count( $array ) : ( $index + 1 );

        if ( empty( $array ) || self::has_string_keys( $array ) ) {
            $array = \array_slice( $array, 0, $position, true ) + $new_entries + \array_slice( $array, $position, null, true );
        } else {
            \array_splice( $array, $position, 0, $new_entries );
        }

        return $array;
    }

    /**
     * Returns all the entries in a given array that match a given needle.
     *
     * @since   1.0.0
     * @version 1.4.0
     *
     * @param   array           $array      Array to search through.
     * @param   mixed           $needle     The value to search for.
     * @param   callable|null   $callback   Optional callback to run the value through before needle comparison.
     * @param   bool            $strict     Whether to perform type checks or not.
     *
     * @return  array|null
     */
    public static function search_values( array $array, $needle, ?callable $callback = null, bool $strict = true ): ?array {
        $comparison_array = \is_callable( $callback ) ? \array_map( $callback, $array ) : $array;

        foreach ( $comparison_array as $key => $value ) {
            if ( ( $strict && $needle === $value ) || ( ! $strict && $needle == $value ) ) { // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
                continue;
            }

            unset( $array[ $key ] );
        }

        return empty( $array ) ? null : $array;
    }

    /**
     * Returns all the keys in a given array that match a given needle.
     *
     * @since   1.0.0
     * @version 1.0.0
     *
     * @param   array           $array      Array whose keys to search through.
     * @param   mixed           $needle     The value to search for.
     * @param   callable|null   $callback   Optional callback to run the key through before needle comparison.
     * @param   bool            $strict     Whether to perform type checks or not.
     *
     * @return  array|null
     */
    public static function search_keys( array $array, $needle, ?callable $callback = null, bool $strict = false ): ?array {
        return self::search_values( \array_keys( $array ), $needle, $callback, $strict );
    }
}