├── _config.yml ├── .gitignore ├── config └── arrayed.php ├── src ├── Types │ └── Undefined.php ├── Exceptions │ └── ArrayedException.php ├── Providers │ └── ArrayedServiceProvider.php ├── Interfaces │ └── ArrayedInterface.php ├── Traits │ └── ArrayPrefix.php └── Arrayed.php ├── .travis.yml ├── dockerizer.sh ├── phpcs.xml ├── docker-compose.yml ├── phpunit.xml ├── Dockerfile ├── .github └── workflows │ └── ci.yml ├── LICENSE ├── Helpers └── helpers.php ├── composer.json ├── docs └── ArrayMethods.md ├── tests ├── ArrayPrefixTraitTest.php └── ArrayedTest.php └── README.md /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-minimal -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .bash_history 2 | /vendor 3 | .phpunit.result.cache 4 | /.idea 5 | .vscode 6 | .composer 7 | composer.lock -------------------------------------------------------------------------------- /config/arrayed.php: -------------------------------------------------------------------------------- 1 | '\\Illuminate\\Support\\Collection', 6 | ]; -------------------------------------------------------------------------------- /src/Types/Undefined.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | Arrayed CodeSniffer config file 4 | 5 | 6 | 7 | ./src 8 | ./tests 9 | 10 | */vendor/* 11 | *.(css|js|sh|phar|json|lock|cache|yml|Dockerfile|md) 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | arrayed: 5 | build: 6 | context: . 7 | dockerfile: Dockerfile 8 | container_name: arrayed 9 | restart: unless-stopped 10 | tty: true 11 | working_dir: /var/www/html 12 | environment: 13 | SERVICE_TAGS: dev 14 | SERVICE_NAME: arrayed 15 | volumes: 16 | - ./:/var/www/html 17 | networks: 18 | - arrayed-network 19 | 20 | #Docker Networks 21 | networks: 22 | arrayed-network: 23 | driver: bridge -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | ./tests/ 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/Providers/ArrayedServiceProvider.php: -------------------------------------------------------------------------------- 1 | publishes([ 19 | __DIR__ . '/../../config/arrayed.php' => config_path('arrayed.php'), 20 | ], 'arrayed'); 21 | 22 | $this->app->bind(ArrayedInterface::class, Arrayed::class); 23 | } 24 | 25 | public function register() 26 | { 27 | $this->mergeConfigFrom(__DIR__ . '/../../config/arrayed.php', 'arrayed'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Set master image 2 | FROM php:7.2-fpm-alpine 3 | 4 | # Copy composer.lock and composer.json 5 | COPY composer.json /var/www/html/ 6 | 7 | # Set working directory 8 | WORKDIR /var/www/html 9 | 10 | # Install Additional dependencies 11 | RUN apk update && apk add --no-cache \ 12 | build-base shadow vim curl \ 13 | php7 \ 14 | php7-fpm \ 15 | php7-common \ 16 | php7-mcrypt \ 17 | php7-mbstring \ 18 | php7-xml \ 19 | php7-openssl \ 20 | php7-json \ 21 | php7-phar \ 22 | php7-zip \ 23 | php7-gd \ 24 | php7-dom \ 25 | php7-session \ 26 | php7-zlib 27 | 28 | # Add and Enable PHP-PDO Extenstions 29 | 30 | # Install PHP Composer 31 | RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer 32 | 33 | # Remove Cache 34 | RUN rm -rf /var/cache/apk/* -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: PHP Composer 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v4 19 | 20 | - name: Validate composer.json and composer.lock 21 | run: composer validate --strict 22 | 23 | - name: Cache Composer packages 24 | id: composer-cache 25 | uses: actions/cache@v3 26 | with: 27 | path: vendor 28 | key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} 29 | restore-keys: | 30 | ${{ runner.os }}-php- 31 | 32 | - name: Install dependencies 33 | run: composer install --prefer-dist --no-progress 34 | 35 | # Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit" 36 | # Docs: https://getcomposer.org/doc/articles/scripts.md 37 | 38 | - name: Run test suite 39 | run: vendor/bin/phpunit 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 transprime-research 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Helpers/helpers.php: -------------------------------------------------------------------------------- 1 | Up to firs level without Laravel config 24 | * 25 | * @param $value 26 | * @param null $default 27 | * @return mixed 28 | */ 29 | function configured($value, $default = null) 30 | { 31 | if (function_exists('config')) { 32 | return config($value, $default); 33 | } 34 | 35 | $keys = explode('.', $value); 36 | 37 | $data = require (__DIR__.'/../config/'.$keys[0].'.php'); 38 | 39 | foreach ($keys as $index => $key) { 40 | if ($index < 1) { 41 | continue; 42 | } 43 | 44 | return $data[$key] ?? $default; 45 | } 46 | 47 | return $data; 48 | } 49 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "transprime-research/arrayed", 3 | "description": "PHP Array(ed) in object oriented way wrapping PHP arrays in a consistent manner.", 4 | "license": "MIT", 5 | "keywords": [ 6 | "php", 7 | "Arrayed", 8 | "Arrays", 9 | "Array", 10 | "Helpers", 11 | "Laravel" 12 | ], 13 | "homepage": "https://transprime-research.github.io/arrayed/", 14 | "support": { 15 | "issues": "https://github.com/transprime-research/arrayed/issues", 16 | "source": "https://github.com/transprime-research/arrayed/issues" 17 | }, 18 | "authors": [ 19 | { 20 | "name": "Oluwatobi Samuel Omisakin", 21 | "email": "omisakin.oluwatobi@gmail.com" 22 | } 23 | ], 24 | "require": { 25 | "php": ">=7.4", 26 | "transprime-research/piper": "^2.0" 27 | }, 28 | "require-dev": { 29 | "phpunit/phpunit": ">=8.0", 30 | "squizlabs/php_codesniffer": "3.*", 31 | "illuminate/support": ">=5.5", 32 | "ext-json": "*", 33 | "symfony/var-dumper": "^6.4" 34 | }, 35 | "autoload": { 36 | "psr-4": { 37 | "Transprime\\Arrayed\\": "src" 38 | }, 39 | "files": [ 40 | "Helpers/helpers.php" 41 | ] 42 | }, 43 | "autoload-dev": { 44 | "psr-4": { 45 | "Transprime\\Arrayed\\Tests\\": "tests/" 46 | } 47 | }, 48 | "minimum-stability": "dev", 49 | "prefer-stable": true, 50 | "extra": { 51 | "laravel": { 52 | "providers": [ 53 | "Transprime\\Arrayed\\Providers\\ArrayedServiceProvider" 54 | ] 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Interfaces/ArrayedInterface.php: -------------------------------------------------------------------------------- 1 | setResult(array_change_key_case($this->getWorkableItem(), $case)); 25 | } 26 | 27 | public function chunk(int $size, bool $preserve_keys = false): ArrayedInterface 28 | { 29 | return $this->setResult(array_chunk($this->getWorkableItem(), $size, $preserve_keys)); 30 | } 31 | 32 | public function column($column, $index_key = null): ArrayedInterface 33 | { 34 | return $this->setResult(array_column($this->getWorkableItem(), $column, $index_key)); 35 | } 36 | 37 | public function countValues(): ArrayedInterface 38 | { 39 | return $this->setResult(array_count_values($this->getWorkableItem())); 40 | } 41 | 42 | public function diffAssoc(array $array2, array ...$_): ArrayedInterface 43 | { 44 | return $this->setResult(array_diff_assoc($this->getWorkableItem(), $array2, ...$_)); 45 | } 46 | 47 | public function diff(array $array2, array ...$_): ArrayedInterface 48 | { 49 | return $this->setResult(array_diff($this->getWorkableItem(), $array2, ...$_)); 50 | } 51 | 52 | public function reverse(bool $preserve_keys = false): ArrayedInterface 53 | { 54 | return $this->setResult(array_reverse($this->getWorkableItem(), $preserve_keys)); 55 | } 56 | 57 | public function diffUassoc(callable $key_compare_func, array $array2, array ...$_): ArrayedInterface 58 | { 59 | return $this->setResult(array_diff_uassoc($this->getWorkableItem(), $array2, ...$_, ...[$key_compare_func])); 60 | } 61 | 62 | public function diffKey(array $array2, array ...$_): ArrayedInterface 63 | { 64 | return $this->setResult(array_diff_key($this->getWorkableItem(), $array2, ...$_)); 65 | } 66 | 67 | public function walk(callable $callable, $arg = null) 68 | { 69 | $workableItem = $this->getWorkableItem(); 70 | array_walk($workableItem, function (&$value, $key, $arg) use ($callable) { 71 | $value = $callable($value, $key, $arg); 72 | }, $arg); 73 | 74 | return $this->setResult($workableItem); 75 | } 76 | 77 | 78 | public function walkRecursive(callable $callable, $arg = null) 79 | { 80 | $workableItem = $this->getWorkableItem(); 81 | array_walk_recursive($workableItem, function (&$value, $key, $arg) use ($callable) { 82 | $value = $callable($value, $key, $arg); 83 | }, $arg); 84 | 85 | return $this->setResult($workableItem); 86 | } 87 | 88 | public function search($needle, bool $strict = true, $default = null) 89 | { 90 | if ($needle instanceof \Closure) { 91 | $result = $this 92 | ->copy() 93 | ->filter(fn($value, $key) => $needle($value, $key)) 94 | ->keys(false); 95 | 96 | return $result->empty() ? $default : $result->offsetGet(0); 97 | } 98 | 99 | 100 | $result = array_search($needle, $this->getWorkableItem(), $strict); 101 | 102 | if ($result === false) { 103 | return $default; 104 | } 105 | 106 | return $result; 107 | } 108 | 109 | 110 | /** 111 | * Like php array_key_exists, this instead search if (one or more) keys exists in the array 112 | * 113 | * @param array $needles - keys to look for in the array 114 | * @param bool $all - [Optional] if false then checks if at least one key is found 115 | * @return bool true if the needle(s) is found else false 116 | */ 117 | public function keysExists(array $needles, bool $all = true): bool 118 | { 119 | $size = arrayed($needles)->count(); 120 | $intersect = $this->keys()->intersect($needles); 121 | 122 | return $all 123 | ? ($intersect->count() === $size) 124 | : (!$intersect->empty()); 125 | } 126 | 127 | /** 128 | * @return ArrayedInterface|mixed 129 | */ 130 | public function head(bool $preserveKeys = false) 131 | { 132 | return self::makeArrayed( 133 | $this->when($this->getWorkableItem()) 134 | ->slice(0, 1, $preserveKeys) 135 | ->values() 136 | ->offsetGet(0) 137 | ); 138 | } 139 | 140 | public function tail(): ArrayedInterface 141 | { 142 | return $this->when($this->getWorkableItem()) 143 | ->slice(1); 144 | } 145 | 146 | private function when($truthyValue, $default = Undefined::class) 147 | { 148 | if ($truthyValue) { 149 | return $this; 150 | } 151 | 152 | if ($default === Undefined::class || $default instanceof Undefined) { 153 | throw new \InvalidArgumentException('Value cannot be resolved'); 154 | } 155 | 156 | return $this->setResult($default); 157 | } 158 | 159 | /** 160 | * Forward the calls to `array_*` that is not yet implemented 161 | *
162 | * Assumption is for those array method that accepts the initial array as the first value 163 | * @param $name 164 | * @param $arguments 165 | * @return mixed 166 | * @throws ArrayedException 167 | */ 168 | public function __call($name, $arguments) 169 | { 170 | // See: https://stackoverflow.com/a/57833019/5704410 171 | $methodName = strtolower(preg_replace("/([a-z])([A-Z])/", "$1_$2", $name)); 172 | $methodName = 'array_' . $methodName; 173 | 174 | if (function_exists($methodName)) { 175 | $result = $methodName($this->getWorkableItem(), ...$arguments); 176 | 177 | return is_array($result) 178 | ? $this->setResult($result) 179 | : $result; 180 | } 181 | 182 | throw new ArrayedException(sprintf('Method %s cannot be resolved', $name)); 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/Arrayed.php: -------------------------------------------------------------------------------- 1 | raw = $this->argumentsToArray(...$values); 25 | 26 | $this->setResult(new Undefined()); 27 | } 28 | 29 | private function argumentsToArray(...$values): array 30 | { 31 | if (func_num_args() === 1 && is_array($values[0])) { 32 | return $values[0]; 33 | } 34 | 35 | if (func_num_args() === 1 && $values[0] instanceof ArrayedInterface) { 36 | return $values[0]->toArray(); 37 | } 38 | 39 | return $values; 40 | } 41 | 42 | public static function on(...$values): ArrayedInterface 43 | { 44 | return new static($values); 45 | } 46 | 47 | public function __invoke(callable $callable = null) 48 | { 49 | return $this->result($callable); 50 | } 51 | 52 | public function map($callback, ...$_): ArrayedInterface 53 | { 54 | return $this->setResult(array_map($callback, $this->getWorkableItem(), ...$_)); 55 | } 56 | 57 | public function filter(Closure $callback = null, int $flag = ARRAY_FILTER_USE_BOTH): ArrayedInterface 58 | { 59 | if ($callback) { 60 | return $this->setResult(array_filter($this->getWorkableItem(), $callback, $flag)); 61 | } 62 | 63 | return $this->setResult(array_filter($this->getWorkableItem())); 64 | } 65 | 66 | public function reduce($function, $initial = null): ArrayedInterface 67 | { 68 | return $this->setResult(array_reduce($this->getWorkableItem(), $function, $initial)); 69 | } 70 | 71 | public function merge(array $array2 = null, ...$_): ArrayedInterface 72 | { 73 | return $this->setResult(array_merge($this->getWorkableItem(), $array2, ...$_)); 74 | } 75 | 76 | public function mergeRecursive(...$_): ArrayedInterface 77 | { 78 | return $this->setResult(array_merge_recursive($this->getWorkableItem(), ...$_)); 79 | } 80 | 81 | public function flip(): ArrayedInterface 82 | { 83 | return $this->setResult(array_flip($this->getWorkableItem())); 84 | } 85 | 86 | public function intersect(array $array2, ...$_): ArrayedInterface 87 | { 88 | return $this->setResult(array_intersect($this->getWorkableItem(), $array2, ...$_)); 89 | } 90 | 91 | public function values(): ArrayedInterface 92 | { 93 | return $this->setResult(array_values($this->getWorkableItem())); 94 | } 95 | 96 | public function keys($overwrite = true): ArrayedInterface 97 | { 98 | $keys = array_keys($this->getWorkableItem()); 99 | 100 | if (!$overwrite) { 101 | return $this->makeArrayed($keys); 102 | } 103 | 104 | return $this->setResult($keys); 105 | } 106 | 107 | public function offsetGet($offset) 108 | { 109 | return $this->makeArrayed($this->getWorkableItem()[$offset]); 110 | } 111 | 112 | public function offsetSet($offset, $value): ArrayedInterface 113 | { 114 | return $this->merge([$offset => $value]); 115 | } 116 | 117 | public function offsetUnset($offset): ArrayedInterface 118 | { 119 | $item = $this->getWorkableItem(); 120 | 121 | unset($item[$offset]); 122 | 123 | return $this->setResult($item); 124 | } 125 | 126 | //Scalar returns 127 | 128 | public function sum(): int 129 | { 130 | return array_sum($this->getWorkableItem()); 131 | } 132 | 133 | public function contains($needle, bool $strict = false): bool 134 | { 135 | return in_array($needle, $this->getWorkableItem(), $strict); 136 | } 137 | 138 | public function isArray(): bool 139 | { 140 | return is_array($this->getWorkableItem()); 141 | } 142 | 143 | public function keyExists($key): bool 144 | { 145 | return array_key_exists($key, $this->getWorkableItem()); 146 | } 147 | 148 | public function offsetExists($offset): bool 149 | { 150 | return $this->keyExists($offset); 151 | } 152 | 153 | public function empty(): bool 154 | { 155 | return empty($this->getWorkableItem()); 156 | } 157 | 158 | public function count(): int 159 | { 160 | return count($this->getWorkableItem()); 161 | } 162 | 163 | //Getters to end chained calls 164 | 165 | public function getIterator() 166 | { 167 | return new ArrayIterator($this->getWorkableItem()); 168 | } 169 | 170 | public function pipe(callable $action, ...$parameters) 171 | { 172 | return $this->setResult( 173 | piper($this->getWorkableItem())->to($action, ...$parameters)() 174 | ); 175 | } 176 | 177 | private function setResult($value) 178 | { 179 | $this->result = $value; 180 | 181 | return $this; 182 | } 183 | 184 | public function result(callable $callable = null) 185 | { 186 | return $callable ? $callable($this->result) : $this->getWorkableItem(); 187 | } 188 | 189 | private function getWorkableItem(bool $asArray = false) 190 | { 191 | if ($this->result instanceof Undefined) { 192 | return $this->raw; 193 | } 194 | 195 | if ($asArray && !is_array($this->result)) { 196 | return (array)$this->result; 197 | } 198 | 199 | return $this->result; 200 | } 201 | 202 | private static function makeArrayed($data) 203 | { 204 | return is_array($data) ? new static($data) : $data; 205 | } 206 | 207 | public function raw(): array 208 | { 209 | return $this->raw; 210 | } 211 | 212 | /** 213 | * @inheritDoc 214 | */ 215 | public function initial(): array 216 | { 217 | return $this->raw; 218 | } 219 | 220 | public function __toString(): string 221 | { 222 | return json_encode($this->getWorkableItem(true)); 223 | } 224 | 225 | public function toArray(): array 226 | { 227 | return $this->walkRecursive( 228 | function ($value) { 229 | return $value instanceof ArrayedInterface ? $value->getWorkableItem() : $value; 230 | } 231 | )->result(); 232 | } 233 | 234 | /** 235 | * @inheritDoc 236 | */ 237 | public function jsonSerialize() 238 | { 239 | return $this->getWorkableItem(true); 240 | } 241 | 242 | public function copy(): ArrayedInterface 243 | { 244 | return new static($this->result()); 245 | } 246 | 247 | public function tap(Closure $closure): ArrayedInterface 248 | { 249 | function_exists('tap') ? tap($this->copy(), $closure) : $closure($this->copy()); 250 | 251 | return $this; 252 | } 253 | 254 | /** 255 | * @param $with 256 | * @return mixed 257 | * @throws ArrayedException 258 | */ 259 | public function collect(...$with) 260 | { 261 | $collectionClass = $this->getConfig('collection_class'); 262 | 263 | if ($collectionClass && class_exists($collectionClass)) { 264 | return new $collectionClass($this->copy()->merge($this->argumentsToArray(...$with))->result()); 265 | } 266 | 267 | throw new ArrayedException('Collection class is not set or does not exist'); 268 | } 269 | 270 | private function getConfig($item) 271 | { 272 | return configured("arrayed.$item", null); 273 | } 274 | } 275 | -------------------------------------------------------------------------------- /tests/ArrayPrefixTraitTest.php: -------------------------------------------------------------------------------- 1 | assertEquals( 14 | ['ABC' => 'cde'], 15 | arrayed(['abc' => 'cde'])->changeKeyCase(CASE_UPPER)->result() 16 | ); 17 | } 18 | 19 | public function testChunk() 20 | { 21 | $this->assertEquals( 22 | [[1, 2], [3, 4]], 23 | arrayed(1, 2, 3, 4)->chunk(2)->result() 24 | ); 25 | } 26 | 27 | public function testMap() 28 | { 29 | $array1 = [1, 2]; 30 | $array2 = ['one', 'two']; 31 | 32 | $this->assertEquals( 33 | ['ONE', 'TWO'], 34 | arrayed($array2) 35 | ->map(function ($value) { 36 | return strtoupper($value); 37 | })->result() 38 | ); 39 | 40 | $this->assertEquals( 41 | [ 42 | [1 => 'one'], 43 | [2 => 'two'], 44 | ], 45 | arrayed($array1) 46 | ->map(function ($first, $second) { 47 | return [$first => $second]; 48 | }, $array2) 49 | ->result() 50 | ); 51 | 52 | $this->assertEquals( 53 | [ 54 | [1, 'one'], 55 | [2, 'two'], 56 | ], 57 | arrayed($array1)->map(null, $array2)->result() 58 | ); 59 | } 60 | 61 | public function testColumn() 62 | { 63 | $array = [ 64 | ['a' => 1, 'b' => 4], 65 | ['a' => 2, 'b' => 3], 66 | ]; 67 | 68 | $this->assertEquals( 69 | [4, 3], 70 | arrayed($array)->column('b')->result() 71 | ); 72 | } 73 | 74 | public function testCountValues() 75 | { 76 | $this->assertEquals( 77 | ['a' => 2, 'b' => 2, 1 => 1, 4 => 1], 78 | arrayed(['a', 1, 'b', 4, 'b', 'a'])->countValues()->result() 79 | ); 80 | } 81 | 82 | public function testDiffAssoc() 83 | { 84 | $array2 = ['a' => 2, 'b' => 2]; 85 | $this->assertEquals( 86 | ['c' => 3], 87 | arrayed(['a' => 2, 'c' => 3, 'b' => 2])->diffAssoc($array2)->result() 88 | ); 89 | } 90 | 91 | public function testDiff() 92 | { 93 | $array2 = ['a', 'b']; 94 | $this->assertEquals( 95 | ['c'], 96 | arrayed(['a', 'c', 'b'])->diff($array2)->values()->result() 97 | ); 98 | } 99 | 100 | public function testKeysExists() 101 | { 102 | $this->assertEquals( 103 | true, 104 | arrayed(['a' => 'b', 'c' => 'd'])->keysExists(['a', 'c']) 105 | ); 106 | } 107 | 108 | public function testReverse() 109 | { 110 | $this->assertEquals( 111 | ['c' => 'd', 'a' => 'b'], 112 | arrayed(['a' => 'b', 'c' => 'd'])->reverse()->result() 113 | ); 114 | } 115 | 116 | public function testDiffUassoc() 117 | { 118 | $first = ['a' => 'b', 'c' => 'd']; 119 | $second = ['2' => 'b', 'c' => 'd']; 120 | $third = ['2' => 'b', 'k' => 'd']; 121 | $callback = function ($first, $second) { 122 | return $first === $second; 123 | }; 124 | 125 | $this->assertEquals( 126 | array_diff_uassoc($first, $second, $callback), 127 | arrayed($first)->diffUassoc($callback, $second)->result() 128 | ); 129 | 130 | $this->assertEquals( 131 | array_diff_uassoc($first, $second, $third, $callback), 132 | arrayed($first)->diffUassoc($callback, $second, $third)->result() 133 | ); 134 | } 135 | 136 | public function testDiffKey() 137 | { 138 | $first = ['a' => 'b', 'c' => 'd']; 139 | $second = ['2' => 'b', 'c' => 'd']; 140 | $third = ['2' => 'b', 'k' => 'd', 'm' => 'a']; 141 | $fourth = ['m' => 'b', 'h' => 'd', 's' => 'a']; 142 | 143 | $this->assertEquals( 144 | array_diff_key($first, $second), 145 | arrayed($first)->diffKey($second)->result() 146 | ); 147 | 148 | $this->assertEquals( 149 | array_diff_key($first, $second, $third, $fourth), 150 | arrayed($first)->diffKey($second, $third, $fourth)->result() 151 | ); 152 | } 153 | 154 | public function testWalk(): void 155 | { 156 | $data = ['a' => 'b', 'c' => 'd']; 157 | 158 | $this->assertEquals( 159 | ['a' => 'b-1', 'c' => 'd-1'], 160 | arrayed($data)->walk(function ($value, $key) { 161 | return $value . '-1'; 162 | }) 163 | ->result() 164 | ); 165 | } 166 | 167 | public function testWalkRecursive(): void 168 | { 169 | $data = ['a' => 'b', 'c' => ['d' => 'e']]; 170 | 171 | $this->assertEquals( 172 | ['a' => 'b-1', 'c' => ['d' => 'e-1']], 173 | arrayed($data) 174 | ->walkRecursive(function ($value, $key) { 175 | return $value . '-1'; 176 | }) 177 | ->result() 178 | ); 179 | } 180 | 181 | public function testUnImplementedArrayPrefixFunction() 182 | { 183 | // array_combine 184 | $keys = ['a', 'b']; 185 | $values = ['name', 'data']; 186 | 187 | $this->assertEquals( 188 | array_combine($keys, $values), 189 | arrayed($keys)->combine($values)->result() 190 | ); 191 | 192 | // array_pop 193 | $data = ['a' => 'b', 'c' => 'd']; 194 | 195 | $this->assertEquals( 196 | 'd', 197 | arrayed($data)->pop(), 198 | ); 199 | 200 | // array_shift. 201 | $this->assertEquals( 202 | 'b', 203 | $arr = arrayed($data)->shift(), 204 | ); 205 | } 206 | 207 | public function testHead(): void 208 | { 209 | $data = ['a', 'b', 'c', 'd']; 210 | 211 | $this->assertSame( 212 | 'a', 213 | arrayed($data)->head(), 214 | ); 215 | 216 | $data = ['a' => 'b', 'c' => 'd']; 217 | 218 | $this->assertSame( 219 | 'b', 220 | arrayed($data)->head(), 221 | ); 222 | 223 | // Test empty. 224 | $this->expectException(\InvalidArgumentException::class); 225 | 226 | arrayed([])->head(); 227 | } 228 | 229 | public function testTail(): void 230 | { 231 | $data = ['a', 'b', 'c', 'd']; 232 | 233 | $this->assertSame( 234 | ['b', 'c', 'd'], 235 | arrayed($data)->tail()->result(), 236 | ); 237 | 238 | $data = ['a' => 'b', 'c' => 'd']; 239 | 240 | $this->assertSame( 241 | ['c' => 'd'], 242 | arrayed($data)->tail()->result(), 243 | ); 244 | 245 | // Test empty. 246 | $this->expectException(\InvalidArgumentException::class); 247 | 248 | arrayed([])->tail(); 249 | } 250 | 251 | public function testSearch(): void 252 | { 253 | $data = ['a', 'b', 'c', 'd']; 254 | 255 | $this->assertSame( 256 | 1, 257 | arrayed($data)->search('b'), 258 | ); 259 | 260 | // When there is no matching value. 261 | $this->assertEquals( 262 | null, 263 | arrayed($data)->search('z'), 264 | ); 265 | 266 | // With default value. 267 | $this->assertEquals( 268 | false, 269 | arrayed($data)->search('z', true, false), 270 | ); 271 | 272 | // With callback. 273 | $this->assertEquals( 274 | 1, 275 | arrayed($data)->search(fn($value) => $value === 'b'), 276 | ); 277 | 278 | // Empty with default. 279 | $this->assertEquals( 280 | 'no', 281 | arrayed([])->search( 282 | fn($value) => $value === 'b', 283 | true, 284 | 'no', 285 | ), 286 | ); 287 | 288 | // With key, value, in callback. 289 | $this->assertEquals( 290 | 2, 291 | arrayed($data)->search( 292 | fn($value, $key) => $value === 'c' && $key == 2, 293 | ), 294 | ); 295 | 296 | // Ensure initial result is not overwritten. 297 | $arrayed = arrayed($data); 298 | 299 | $searchResult = $arrayed->search(fn($value, $key) => $value === 'c' && $key === 2); 300 | 301 | $this->assertEquals( 302 | 2, 303 | $searchResult, 304 | ); 305 | 306 | $this->assertEquals( 307 | ['a', 'b', 'c', 'd'], 308 | $arrayed->result(), 309 | ); 310 | } 311 | } 312 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |

6 | Build Status 7 | Latest Stable Version 8 | Total Downloads 9 | Latest Unstable Version 10 | Latest Monthly Downloads 11 | License 12 |

13 | 14 | ## About Arrayed 15 | 16 | Simple PHP Array(ed) in object oriented way wrapping [PHP Arrays](https://www.php.net/manual/en/ref.array.php) in a consistent manner. 17 | > No advanced stuff, just wrap PHP array_* functions and a little more. Do it Like a PRO :ok: 18 | 19 | > Looking for PHP Array on Steroid? See: https://laravel.com/docs/collections 20 | 21 | ## Quick Usage 22 | 23 | ```php 24 | arrayed(1, 2, 'ninja') 25 | ->filter(fn($val) => is_int($val)) // [1,2] 26 | ->map(fn($val) => $val + 1) // [2, 3] 27 | ->flip() // [0, 1] 28 | ->values() // [0, 1] 29 | ->sum(); // 1 30 | ``` 31 | 32 | Instead of: 33 | 34 | ```php 35 | $result = array_filter([1, 2, 'ninja'], fn($val) => is_int($val)); 36 | $result = array_map(fn($val) => $val + 1, $result); 37 | $result = array_flip($result); 38 | $result = array_values($result); 39 | $result = array_sum($result); 40 | ``` 41 | > PS: You can still use the old `function() { return v; }`, `fn()` is the new short arrow function in PHP 7.4+ See: https://www.php.net/manual/en/functions.arrow.php 42 | 43 | ## Installation 44 | 45 | ```shell script 46 | composer require transprime-research/arrayed 47 | ``` 48 | 49 | ## Requirement 50 | Minimum Requirement 51 | - PHP 7.2 + 52 | - Composer 53 | 54 | - For using `collect()` method, requires `illuminate\support` >= 5.5 55 | > Additionally on Laravel App, if `arrayed.php`'s config file doesn't get added automatically then run `php artisan vendor:publish --tag=arrayed` after installation. 56 | 57 | ## Other Usages 58 | 59 | Arrayed can be instantiated in 3 ways: 60 | 61 | ```php 62 | use Transprime\Arrayed\Arrayed; 63 | 64 | // Nifty 65 | arrayed(1, 2)->count(); 66 | 67 | // Easier 68 | Arrayed::on(1, 2)->count(); 69 | 70 | // Normal with (new instance) 71 | (new Arrayed(1,2))->count(); 72 | ``` 73 | 74 | Initial values can be passed in two ways: 75 | 76 | ```php 77 | //Non associative 78 | arrayed(1, 2); 79 | 80 | //OR 81 | arrayed([1, 2]); 82 | 83 | // For associative array, only this way 84 | arrayed(['a' => 1, 'b' => 2]); 85 | ``` 86 | 87 | #### With Laravel & Laravel Collection 88 | 89 | Laravel Collections 90 | 91 | New: `collect()` method :tada: 92 | 93 | ```php 94 | arrayed(1,2)->collect(); // instance of Illuminate/Support/Collection 95 | arrayed(1,2)->collect(3, 4); //merged with first one to give [1, 2, 3, 4] 96 | ``` 97 | > In the future, changing the default Collection class will possible by editing `config/arrayed.php`'s collection_class value 98 | 99 | Others: 100 | 101 | ```php 102 | collect(arrayed(1, 2, 3, 4)); 103 | 104 | // Or 105 | new Collection(arrayed(1, 2, 3, 4)); 106 | 107 | // Or 108 | Collection::make(arrayed(1, 2, 3, 4)); 109 | ``` 110 | 111 | Laravel Response accepts `Arrayed`: 112 | 113 | ```php 114 | response()->json(arrayed(1, 2, 3)->flip()); 115 | ``` 116 | 117 | #### Special methods 118 | 119 | New :tada: `tap()` method allows other actions on the last resulting `Arrayed` instance without mutating the last `Arrayed` result: 120 | 121 | ```php 122 | arrayed(1, 2, 3) 123 | ->tap(function ($arrd) { 124 | logger('Array has '.$arrd->count()); 125 | }); 126 | ``` 127 | 128 | ## Others 129 | 130 | If any operation normally returns an array, the return value will give `Arrayed` instance so that other methods can be chained on them otherwise a non-array value is returned as can be seen that `sum()` returns an integer in the example below: 131 | 132 | Example: 133 | 134 | ```php 135 | arrayed(['a' => 1, 'b' => 2]) 136 | ->values() // returns array, we can chain 137 | ->sum(); // returns an integer, we cannot chain 138 | ``` 139 | 140 | You can work on a result (if its an array'ed value) by passing a closure/callable function to `result()` method: 141 | 142 | ```php 143 | arrayed(['a' => 'name', 'b' => 'age']) 144 | ->values() 145 | ->result(fn($val) => implode(',', $val)); //'name,age' 146 | 147 | //Or 148 | 149 | arrayed(['a' => 'name', 'b' => 'age']) 150 | ->values()(fn($val) => implode(',', $val)); //'name,age' 151 | ``` 152 | 153 | Get the original array data with `raw()` method 154 | 155 | ```php 156 | arrayed([1, 2])->raw(); //[1,2] 157 | ``` 158 | 159 | #### Piped calls 160 | As at now not all `array_*` functions have been implemented. 161 | `pipe()` method helps to call custom function on the array result. 162 | 163 | Such as `array_unique` used in this way: 164 | 165 | ```php 166 | arrayed(['a' => 'www', 'b' => 'dot', 'c' => 'www']) 167 | ->pipe('array_unique') // data is piped forward to `array_unique` 168 | ->flip() 169 | ->values()(); //['a', 'b'] 170 | ``` 171 | > The pipe method makes use of [Piper](https://github.com/transprime-research/piper) - A PHP functional pipe'ing 172 | > See `\Transprime\Arrayed\Tests\ArrayedTest` 173 | 174 | #### Proxied calls 175 | 176 | `array_*` methods that are not yet implemented are automatically proxied to call an array method with the assumption that they accept initial array first. Example is this: 177 | 178 | ```php 179 | // ->combine() method is not yet implemented 180 | 181 | arrayed(['a', 'b']) 182 | ->combine(['name', 'data']) 183 | ->result(); //['a' => 'name', 'b' => 'data'] 184 | ``` 185 | 186 | ## Coming Soon 187 | 188 | - Implement other `array_*` methods 189 | 190 | - pipe into Collection with `collectPipe` 191 | 192 | ```php 193 | use Illuminate\Support\Collection; 194 | 195 | arrayed(1,2,3)->collectPipe(function (Collection $collected) { 196 | return $collected->take(2)->all(); 197 | })->keys(); 198 | ``` 199 | 200 | > Api implementation to be decided 201 | 202 | ## APIs 203 | 204 | These are the API's available: 205 | 206 | ```php 207 | static Arrayed::on(...$values): ArrayedInterface; //new instance of Arrayed 208 | 209 | Arrayed::map($callback): ArrayedInterface; 210 | 211 | Arrayed::filter($callback = null, int $flag = 0): ArrayedInterface; 212 | 213 | Arrayed::reduce($function, $initial = null): ArrayedInterface; 214 | 215 | Arrayed::merge(array $array2 = null, ...$_): ArrayedInterface; 216 | 217 | Arrayed::mergeRecursive(...$_): ArrayedInterface; 218 | 219 | Arrayed::flip(): ArrayedInterface; 220 | 221 | Arrayed::intersect(array $array2, ...$_): ArrayedInterface; 222 | 223 | Arrayed::values(): ArrayedInterface; 224 | 225 | Arrayed::keys($overwrite = true): ArrayedInterface; 226 | 227 | Arrayed::offsetGet($offset); 228 | 229 | Arrayed::offsetSet($offset, $value): ArrayedInterface; 230 | 231 | Arrayed::offsetUnset($offset): ArrayedInterface; 232 | 233 | Arrayed::sum(): int; 234 | 235 | Arrayed::contains($needle, bool $strict = false): bool; 236 | 237 | Arrayed::isArray(): bool; 238 | 239 | Arrayed::keyExists($key): bool; 240 | 241 | Arrayed::offsetExists($offset): bool; 242 | 243 | Arrayed::empty(): bool; 244 | 245 | Arrayed::count(): int; 246 | 247 | Arrayed::pipe(callable $action, ...$parameters); 248 | 249 | Arrayed::result(callable $callable = null); 250 | 251 | Arrayed::raw(): array; 252 | 253 | Arrayed::initial(): array; // Deprecated, use raw() instead 254 | 255 | Arrayed::tap(Closure $closure): ArrayedInterface; 256 | 257 | Arrayed::copy(): ArrayedInterface; 258 | 259 | Arrayed::collect(...$with): array; 260 | 261 | // Other Array_* methods 262 | 263 | Arrayed::changeKeyCase(int $case = null): ArrayedInterface; 264 | 265 | Arrayed::chunk(int $size, bool $preserve_keys = false): ArrayedInterface; 266 | 267 | Arrayed::column($column, $index_key = null): ArrayedInterface; 268 | 269 | Arrayed::countValues(): ArrayedInterface; 270 | 271 | Arrayed::diffAssoc(array $array2, array ...$_): ArrayedInterface; 272 | 273 | Arrayed::diff(array $array2, array ...$_): ArrayedInterface; 274 | 275 | Arrayed::reverse(bool $preserve_keys = false): ArrayedInterface; 276 | 277 | Arrayed::diffUassoc(callable $key_compare_func, array $array2, array ...$_): ArrayedInterface; 278 | 279 | Arrayed::diffKey(array $array2, array ...$_): ArrayedInterface; 280 | 281 | ``` 282 | 283 | ## Additional Information 284 | 285 | This package is part of a series of "Code Dare" 286 | 287 | See other packages in this series here: 288 | 289 | - https://github.com/transprime-research/piper [A functional PHP pipe in object-oriented way] 290 | - https://github.com/omitobi/conditional [A smart PHP if...elseif...else statement] 291 | - https://github.com/transprime-research/attempt [A smart PHP try...catch statement] 292 | - https://github.com/omitobi/corbonate [A smart Carbon + Collection package] 293 | - https://github.com/omitobi/laravel-habitue [Jsonable Http Request(er) package with Collections response] 294 | 295 | ## Similar packages 296 | 297 | - https://github.com/cocur/chain - Very identical, but without Piper 298 | - https://github.com/bocharsky-bw/Arrayzy - Identical but with more actions and features 299 | - https://github.com/voku/Arrayy - Perform more than just an OOP style on Arrays 300 | - https://github.com/dantodev/php-array-tools - array tools plus collections 301 | - https://github.com/minwork/array - Pack of advanced PHP array functions 302 | - https://github.com/mblarsen/arrgh - A Sane PHP Array library with advance functions 303 | - More at: https://www.google.com/search?q=php+array+github 304 | 305 | ## Licence 306 | 307 | MIT (See LICENCE file) 308 | -------------------------------------------------------------------------------- /tests/ArrayedTest.php: -------------------------------------------------------------------------------- 1 | assertIsObject(new Arrayed()); 15 | } 16 | 17 | public function testIsArrayed() 18 | { 19 | $this->assertInstanceOf(ArrayedInterface::class, new Arrayed()); 20 | $this->assertInstanceOf(ArrayedInterface::class, arrayed()); 21 | $this->assertInstanceOf(ArrayedInterface::class, Arrayed::on()); 22 | } 23 | 24 | public function testInitialDataIsCorrectlyRetrieved() 25 | { 26 | $data = ['1', 2]; 27 | $data2 = ['1', 2]; 28 | 29 | $this->assertSame(arrayed($data)->keys()->raw(), $data); 30 | $this->assertSame(arrayed(...$data2)->keys()->raw(), $data2); 31 | } 32 | 33 | public function testSum() 34 | { 35 | $this->assertEquals(3, arrayed(1, 2)->sum()); 36 | $this->assertEquals( 37 | 5, 38 | arrayed(1, 2, 'ninja') 39 | ->filter(function ($val) { 40 | return is_int($val); 41 | }) 42 | ->map(function ($val) { 43 | return $val + 1; 44 | }) 45 | ->sum() 46 | ); 47 | } 48 | 49 | public function testPassingAnArray() 50 | { 51 | $this->assertEquals( 52 | 5, 53 | arrayed([1, 2, 'ninja']) 54 | ->filter(function ($val) { 55 | return is_int($val); 56 | }) 57 | ->map(function ($val) { 58 | return $val + 1; 59 | }) 60 | ->sum() 61 | ); 62 | } 63 | 64 | public function testReduce() 65 | { 66 | $this->assertEquals( 67 | 6, 68 | arrayed([1, 2, 3]) 69 | ->reduce(function ($acc, $item) { 70 | return $acc + $item; 71 | }, 0)() 72 | ); 73 | 74 | $this->assertEquals( 75 | 7, 76 | arrayed(1, 2) 77 | ->map(function ($i) { 78 | return $i + 1; 79 | }) 80 | ->reduce(function ($v, $i) { 81 | return $v + $i; 82 | }, 2)() 83 | ); 84 | } 85 | 86 | public function testOffsetMethods() 87 | { 88 | $this->assertEquals( 89 | 1, 90 | arrayed(['a' => 1, 'b' => 2]) 91 | ->offsetGet('a') 92 | ); 93 | 94 | $this->assertEquals( 95 | ['z' => 1], 96 | arrayed(['a' => ['z' => 1], 'b' => 2]) 97 | ->offsetGet('a')() 98 | ); 99 | 100 | $this->assertTrue( 101 | arrayed(['a' => ['z' => 1], 'b' => 2]) 102 | ->offsetExists('b') 103 | ); 104 | 105 | $this->assertEquals( 106 | 3, 107 | arrayed(['a' => ['z' => 1], 'b' => 2]) 108 | ->offsetSet('c', 3) 109 | ->count() 110 | ); 111 | 112 | $this->assertEquals( 113 | ['b' => 2], 114 | arrayed(['a' => ['z' => 1], 'b' => 2]) 115 | ->offsetUnset('a')() 116 | ); 117 | } 118 | 119 | public function testMergeMethod() 120 | { 121 | $this->assertCount( 122 | 4, 123 | arrayed(['a' => 1, 'b' => 2]) 124 | ->merge(['z' => 26]) 125 | ->merge(['c' => 2])() 126 | ); 127 | 128 | $this->assertCount( 129 | 4, 130 | arrayed(['a' => 1, 'b' => 2]) 131 | ->merge(['z' => 26], ['c' => 2])() 132 | ); 133 | 134 | $names = arrayed(['cdd']); 135 | $names = arrayed($names) 136 | ->merge(['abc']); 137 | 138 | $this->assertEquals( 139 | array_merge(['cdd'], ['abc']), 140 | $names->toArray(), 141 | ); 142 | } 143 | 144 | public function testAccessibleArray() 145 | { 146 | $this->assertCount( 147 | 2, 148 | arrayed(['a' => 1, 'b' => 2]) 149 | ); 150 | 151 | $this->assertEquals( 152 | 2, 153 | arrayed(['a' => 1, 'b' => 2])['b'] 154 | ); 155 | 156 | // Until its PHP 7.4 157 | // $this->assertCount( 158 | // 2, 159 | // [...arrayed([1, 2])] 160 | // ); 161 | 162 | [$a,] = arrayed([1, 2]); 163 | $this->assertEquals( 164 | 1, 165 | $a 166 | ); 167 | 168 | $this->assertTrue( 169 | arrayed([])->empty() 170 | ); 171 | } 172 | 173 | public function testMergeRecursiveMethod() 174 | { 175 | $this->assertCount( 176 | 2, 177 | arrayed(['a' => 1, 'b' => 2]) 178 | ->merge(['b' => 4]) 179 | ->mergeRecursive(['b' => 5]) 180 | ->offsetGet('b') //[4, 5]] 181 | ); 182 | } 183 | 184 | public function testFlipMethod() 185 | { 186 | $this->assertEquals( 187 | 'b', 188 | arrayed(['a' => 1, 'b' => 2]) 189 | ->flip() 190 | ->offsetGet(2) //b 191 | ); 192 | } 193 | 194 | public function testIntersectMethod() 195 | { 196 | $this->assertCount( 197 | 1, 198 | arrayed(['a' => 'z', 'b' => 'y']) 199 | ->flip() 200 | ->intersect(['z' => 'a']) 201 | ); 202 | 203 | $this->assertCount( 204 | 2, 205 | arrayed(['a' => 'z', 'b' => 'y', 'c']) 206 | ->intersect(arrayed(['a' => 'z', 'c', 'm'])()) 207 | ); 208 | 209 | $this->assertCount( 210 | 1, 211 | arrayed(['a' => 'z', 'b' => 'y', 'c']) 212 | ->flip() 213 | ->intersect(['a', 0], [0]) 214 | ); 215 | 216 | $this->assertCount( 217 | 1, 218 | arrayed(['a' => 'z', 'b' => 'y', 'c']) 219 | ->flip() 220 | ->intersect(['a', 0]) 221 | ->intersect([0]) 222 | ); 223 | } 224 | 225 | public function testValuesMethod() 226 | { 227 | $this->assertEquals( 228 | ['a', 'b'], 229 | arrayed(['a' => 'z', 'b' => 'y']) 230 | ->flip() 231 | ->values()() 232 | ); 233 | 234 | $this->assertSameSize( 235 | ['a', 'b'], 236 | arrayed(['a' => 'z', 'b' => 'y']) 237 | ->flip() 238 | ->values() 239 | ); 240 | } 241 | 242 | public function testKeysMethod() 243 | { 244 | $this->assertEquals( 245 | ['z', 'y'], 246 | arrayed(['a' => 'z', 'b' => 'y']) 247 | ->flip() 248 | ->keys()() 249 | ); 250 | } 251 | 252 | public function testContainsMethod() 253 | { 254 | $this->assertTrue( 255 | arrayed(['a' => 'z', 'b' => 'y']) 256 | ->contains('y') 257 | ); 258 | 259 | $this->assertTrue( 260 | arrayed(['a' => 'www', 'b' => 'dot', 'c' => null]) 261 | ->contains('') 262 | ); 263 | 264 | $this->assertFalse( 265 | arrayed(['a' => 'www', 'b' => 'dot', 'c' => null]) 266 | ->contains('', true) 267 | ); 268 | } 269 | 270 | public function testUsingArrayedAsConstructorValues() 271 | { 272 | $this->assertEquals( 273 | 5, 274 | arrayed(\arrayed(1), \arrayed(2)) 275 | ->map(function ($i) { 276 | return $i[0] + 1; 277 | }) 278 | ->sum() 279 | ); 280 | } 281 | 282 | public function testWithPiper() 283 | { 284 | $this->assertEquals( 285 | ['c' => 'com'], 286 | arrayed(['a' => 'www', 'b' => 'dot']) 287 | ->flip() 288 | ->pipe('array_diff', ['www' => 'a', 'c' => 'com'])() 289 | ); 290 | 291 | $this->assertEquals( 292 | ['com' => 1], 293 | arrayed(['a' => 'www', 'b' => 'dot']) 294 | ->flip() 295 | ->pipe('array_diff', ['www' => 'a', 'c' => 'com']) 296 | ->pipe('array_count_values')() 297 | ); 298 | 299 | $this->assertEquals( 300 | ['a', 'b'], 301 | arrayed(['a' => 'www', 'b' => 'dot', 'c' => 'www']) 302 | ->pipe('array_unique') 303 | ->flip() 304 | ->values()() 305 | ); 306 | } 307 | 308 | public function testExtraCallableOnResultMethod() 309 | { 310 | $this->assertEquals( 311 | 'name,age', 312 | arrayed(['a' => 'name', 'b' => 'age']) 313 | ->values() 314 | ->result(function ($val) { 315 | return implode(',', $val); 316 | }) 317 | ); 318 | 319 | $this->assertEquals( 320 | 'name,age', 321 | arrayed(['a' => 'name', 'b' => 'age']) 322 | ->values()(function ($val) { 323 | return implode(',', $val); 324 | }) 325 | ); 326 | 327 | $this->assertEquals( 328 | 'nameage', 329 | arrayed(['a' => 'name', 'b' => 'age']) 330 | ->values() 331 | ->result('implode') 332 | ); 333 | } 334 | 335 | public function testJsonable() 336 | { 337 | $data = ['a' => 1, 'b' => 2]; 338 | 339 | $this->assertJson((string) arrayed($data)); 340 | $this->assertStringContainsString((string) arrayed($data), json_encode($data)); 341 | $this->assertEquals(json_encode($data), arrayed($data)); 342 | $this->assertSame(json_encode($data), json_encode(arrayed($data))); 343 | } 344 | 345 | public function testCopy() 346 | { 347 | $arrayed = arrayed(1, 2, 3); 348 | 349 | $this->assertEquals($arrayed, $arrayed->copy()); 350 | $this->assertNotSame($arrayed, $arrayed->copy()); 351 | } 352 | 353 | public function testTap() 354 | { 355 | $res = []; 356 | $arrayed = arrayed(1, 2, 3) 357 | ->tap(function ($arrd) use (&$res) { 358 | $res = $arrd->reverse(); 359 | }); 360 | 361 | $this->assertEquals($arrayed[0], $res[2]); 362 | } 363 | 364 | public function testCollect() 365 | { 366 | $this->assertIsObject( 367 | arrayed(1, 2, 3) 368 | ->collect() 369 | ); 370 | 371 | $this->assertEquals( 372 | 6, 373 | arrayed(1, 2, 3) 374 | ->collect(2, 3, 4) 375 | ->count() 376 | ); 377 | } 378 | } 379 | --------------------------------------------------------------------------------