├── .gitignore ├── src ├── Exceptions │ └── CollectionItemNotFound.php ├── Macros │ ├── Collection │ │ ├── Head.php │ │ ├── Eighth.php │ │ ├── Fifth.php │ │ ├── Fourth.php │ │ ├── Ninth.php │ │ ├── Second.php │ │ ├── Sixth.php │ │ ├── Tenth.php │ │ ├── Third.php │ │ ├── Seventh.php │ │ ├── At.php │ │ ├── Trim.php │ │ ├── FilterMap.php │ │ ├── Glob.php │ │ ├── ToPairs.php │ │ ├── CollectBy.php │ │ ├── PluckToArray.php │ │ ├── Before.php │ │ ├── Tail.php │ │ ├── IfAny.php │ │ ├── IfEmpty.php │ │ ├── Carbonize.php │ │ ├── TransformKeys.php │ │ ├── WithSize.php │ │ ├── ChunkBy.php │ │ ├── None.php │ │ ├── Prioritize.php │ │ ├── FromPairs.php │ │ ├── FirstOrFail.php │ │ ├── Extract.php │ │ ├── Rotate.php │ │ ├── After.php │ │ ├── EachCons.php │ │ ├── SimplePaginate.php │ │ ├── GroupByModel.php │ │ ├── ParallelMap.php │ │ ├── Paginate.php │ │ ├── SectionBy.php │ │ ├── Validate.php │ │ ├── Transpose.php │ │ └── SliceBefore.php │ ├── Blade │ │ ├── Blank.php │ │ └── Filled.php │ └── Stringable │ │ ├── Get.php │ │ ├── ToArray.php │ │ ├── Count.php │ │ ├── Collapse.php │ │ ├── AppendIf.php │ │ ├── PrependIf.php │ │ ├── Toggle.php │ │ ├── Insert.php │ │ ├── PadLeft.php │ │ ├── PadRight.php │ │ ├── Segment.php │ │ └── Possessive.php └── ServiceProvider.php ├── tests ├── Stringable │ ├── GetTest.php │ ├── ToArrayTest.php │ ├── CollapseTest.php │ ├── AppendIfTest.php │ ├── PadLeftTest.php │ ├── PadRightTest.php │ ├── PrependIfTest.php │ ├── CountTest.php │ ├── ToggleTest.php │ ├── PossessiveTest.php │ ├── InsertTest.php │ └── SegmentTest.php ├── Collection │ ├── TrimTest.php │ ├── FilterMapTest.php │ ├── TransformKeysTest.php │ ├── CarbonizeTest.php │ ├── FirstOrFailTest.php │ ├── WithSizeTest.php │ ├── HeadTest.php │ ├── AtTest.php │ ├── ToPairsTest.php │ ├── FromPairsTest.php │ ├── PluckToArrayTest.php │ ├── ValidateTest.php │ ├── ExtractTest.php │ ├── AfterTest.php │ ├── BeforeTest.php │ ├── IfAnyTest.php │ ├── IfEmptyTest.php │ ├── SimplePaginateTest.php │ ├── NoneTest.php │ ├── EachConsTest.php │ ├── RotateTest.php │ ├── CollectByTest.php │ ├── PrioritizeTest.php │ ├── TailTest.php │ ├── PaginateTest.php │ ├── ChunkByTest.php │ ├── GetHumanCountTest.php │ ├── SectionByTest.php │ ├── SliceBeforeTest.php │ ├── TransposeTest.php │ └── GroupByModelTest.php ├── Blade │ ├── BlankTest.php │ └── FilledTest.php └── RegisterTest.php ├── phpunit.xml ├── .github ├── workflows │ ├── style.yml │ └── tests.yml └── .php-cs-fixer.php ├── LICENSE.md ├── composer.json ├── config └── elevate.php ├── README.md └── .php-cs-fixer.cache /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | composer.lock 3 | vendor 4 | .DS_Store 5 | coverage 6 | .phpunit.result.cache 7 | .idea 8 | .php_cs.cache 9 | TODO.md -------------------------------------------------------------------------------- /src/Exceptions/CollectionItemNotFound.php: -------------------------------------------------------------------------------- 1 | $this->first()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Macros/Blade/Blank.php: -------------------------------------------------------------------------------- 1 | blank($expression)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Macros/Blade/Filled.php: -------------------------------------------------------------------------------- 1 | blank($expression)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Macros/Collection/Eighth.php: -------------------------------------------------------------------------------- 1 | $this->get(7)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Macros/Collection/Fifth.php: -------------------------------------------------------------------------------- 1 | $this->get(4)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Macros/Collection/Fourth.php: -------------------------------------------------------------------------------- 1 | $this->get(3)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Macros/Collection/Ninth.php: -------------------------------------------------------------------------------- 1 | $this->get(8)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Macros/Collection/Second.php: -------------------------------------------------------------------------------- 1 | $this->get(1)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Macros/Collection/Sixth.php: -------------------------------------------------------------------------------- 1 | $this->get(5)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Macros/Collection/Tenth.php: -------------------------------------------------------------------------------- 1 | $this->get(9)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Macros/Collection/Third.php: -------------------------------------------------------------------------------- 1 | $this->get(2)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Macros/Stringable/Get.php: -------------------------------------------------------------------------------- 1 | $this->__toString()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Macros/Collection/Seventh.php: -------------------------------------------------------------------------------- 1 | $this->get(6)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Macros/Collection/At.php: -------------------------------------------------------------------------------- 1 | $this->slice($index, 1)->first()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Macros/Collection/Trim.php: -------------------------------------------------------------------------------- 1 | $this->map(fn ($value) => trim($value))); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Macros/Stringable/ToArray.php: -------------------------------------------------------------------------------- 1 | str_split($this->__toString())); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Macros/Collection/FilterMap.php: -------------------------------------------------------------------------------- 1 | $this->map($callback)->filter()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Macros/Stringable/Count.php: -------------------------------------------------------------------------------- 1 | mb_substr_count($this->__toString(), $search)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Macros/Collection/Glob.php: -------------------------------------------------------------------------------- 1 | Collection::make(glob($pattern, $flags))); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Macros/Collection/ToPairs.php: -------------------------------------------------------------------------------- 1 | $this->keys()->map(fn ($key) => [$key, $this->items[$key]])); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Macros/Collection/CollectBy.php: -------------------------------------------------------------------------------- 1 | new Collection($this->get($key, $default))); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Macros/Collection/PluckToArray.php: -------------------------------------------------------------------------------- 1 | $this->pluck($value, $key)->toArray()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Macros/Stringable/Collapse.php: -------------------------------------------------------------------------------- 1 | __toString(), 'msr'))); 17 | }); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Macros/Collection/Before.php: -------------------------------------------------------------------------------- 1 | 18 | $this->reverse()->after($currentItem, $fallback) 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Macros/Collection/Tail.php: -------------------------------------------------------------------------------- 1 | 18 | ! $preserveKeys ? $this->slice(1)->values() : $this->slice(1) 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Macros/Collection/IfAny.php: -------------------------------------------------------------------------------- 1 | isEmpty()) { 17 | $callback($this); 18 | } 19 | 20 | return $this; 21 | }); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Macros/Collection/IfEmpty.php: -------------------------------------------------------------------------------- 1 | isEmpty()) { 17 | $callback($this); 18 | } 19 | 20 | return $this; 21 | }); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Macros/Collection/Carbonize.php: -------------------------------------------------------------------------------- 1 | 19 | collect($this->items)->map(fn ($time) => new CarbonImmutable($time)) 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Macros/Collection/TransformKeys.php: -------------------------------------------------------------------------------- 1 | 18 | collect($this->items)->mapWithKeys(fn ($item, $key) => [$operation($key) => $item]) 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Macros/Collection/WithSize.php: -------------------------------------------------------------------------------- 1 | sliceBefore(fn ($item, $prevItem) => 17 | $callback($item) !== $callback($prevItem), $preserveKeys); 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Macros/Collection/None.php: -------------------------------------------------------------------------------- 1 | contains($key, $value); 18 | } 19 | 20 | return ! $this->contains($key); 21 | }); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Macros/Collection/Prioritize.php: -------------------------------------------------------------------------------- 1 | reject($callable); 17 | 18 | return $this 19 | ->filter($callable) 20 | ->union($nonPrioritized); 21 | }); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Macros/Stringable/AppendIf.php: -------------------------------------------------------------------------------- 1 | __toString(), $text) ? $this->__toString() : $this->__toString() . $text 19 | ); 20 | }); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Macros/Stringable/PrependIf.php: -------------------------------------------------------------------------------- 1 | __toString(), $text) ? $this->__toString() : $text . $this->__toString() 19 | ); 20 | }); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/Stringable/GetTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('test', Str::of('test')->get()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Macros/Collection/FromPairs.php: -------------------------------------------------------------------------------- 1 | reduce(function($assoc, $keyValuePair) { 17 | [$key, $value] = $keyValuePair; 18 | $assoc[$key] = $value; 19 | 20 | return $assoc; 21 | }, new Collection); 22 | }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/Stringable/ToArrayTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(['f', 'o', 'o'], Str::of('foo')->toArray()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Macros/Collection/FirstOrFail.php: -------------------------------------------------------------------------------- 1 | first())) { 18 | return $item; 19 | } 20 | 21 | throw new CollectionItemNotFound('No items found in collection.'); 22 | }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/Stringable/CollapseTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('h e l l o', Str::of(' h e l l o ')->collapse()->get()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Macros/Stringable/Toggle.php: -------------------------------------------------------------------------------- 1 | __toString(), [$first, $second], true)) { 17 | return $this; 18 | } 19 | 20 | return $this->__toString() === $first ? new Stringable($second) : new Stringable($first); 21 | }); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Macros/Stringable/Insert.php: -------------------------------------------------------------------------------- 1 | length() < $index ? $this->length() : $index; 17 | 18 | $before = mb_substr($this->__toString(), 0, $index); 19 | 20 | $after = mb_substr($this->__toString(), $index); 21 | 22 | return new Stringable($before . $text . $after); 23 | }); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Macros/Collection/Extract.php: -------------------------------------------------------------------------------- 1 | 21 | $extracted->push(data_get($this->items, $key)), 22 | new Collection() 23 | ); 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/Collection/TrimTest.php: -------------------------------------------------------------------------------- 1 | assertEquals($clean, collect($padded)->trim()->toArray()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | src/ 6 | 7 | 8 | 9 | 10 | tests 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /tests/Stringable/AppendIfTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('foobar', Str::of('foo')->appendIf('bar')->get()); 24 | $this->assertEquals('foobar', Str::of('foobar')->appendIf('bar')->get()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/Stringable/PadLeftTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(' ABC', Str::of('ABC')->padLeft(10)->get()); 24 | $this->assertEquals(' ABC', Str::of(' ABC')->padLeft(10)->get()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/Stringable/PadRightTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('ABC ', Str::of('ABC')->padRight(10)->get()); 24 | $this->assertEquals('ABC ', Str::of('ABC ')->padRight(10)->get()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/Stringable/PrependIfTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('foobar', Str::of('bar')->prependIf('foo')->get()); 24 | $this->assertEquals('foobar', Str::of('foobar')->prependIf('foo')->get()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/Stringable/CountTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(1, Str::of('foo')->count('f')); 24 | $this->assertEquals(2, Str::of('foo')->count('o')); 25 | $this->assertEquals(0, Str::of('foo')->count('b')); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/ServiceProvider.php: -------------------------------------------------------------------------------- 1 | publishes([__DIR__ . '/../config/elevate.php' => config_path('elevate.php')]); 16 | 17 | $this->mergeConfigFrom(__DIR__ . '/../config/elevate.php', 'elevate'); 18 | 19 | foreach (config('elevate') as $class => $macros) { 20 | foreach ($macros as $macro => $use) { 21 | $use ? ("Elevate\\Macros\\$class\\$macro")::register() : null; 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Macros/Collection/Rotate.php: -------------------------------------------------------------------------------- 1 | isEmpty()) { 17 | return new Collection; 18 | } 19 | 20 | $count = $this->count(); 21 | 22 | $offset %= $count; 23 | 24 | if ($offset < 0) { 25 | $offset += $count; 26 | } 27 | 28 | return new Collection($this->slice($offset)->merge($this->take($offset))); 29 | }); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Macros/Stringable/PadLeft.php: -------------------------------------------------------------------------------- 1 | length()); 17 | $pad_length = mb_strlen($character); 18 | 19 | return new Stringable( 20 | str_repeat($character, (int) ($length / $pad_length)) . 21 | mb_substr($character, 0, $length % $pad_length) . 22 | $this->__toString() 23 | ); 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Macros/Stringable/PadRight.php: -------------------------------------------------------------------------------- 1 | length()); 17 | $pad_length = mb_strlen($character); 18 | 19 | return new Stringable( 20 | $this->__toString() . 21 | str_repeat($character, (int) ($length / $pad_length)) . 22 | mb_substr($character, 0, $length % $pad_length) 23 | ); 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Macros/Stringable/Segment.php: -------------------------------------------------------------------------------- 1 | __toString()); 17 | 18 | if ($index < 0) { 19 | $segments = array_reverse($segments); 20 | $index = abs($index) - 1; 21 | } 22 | 23 | $segment = isset($segments[$index]) ? $segments[$index] : ''; 24 | 25 | return new Stringable($segment); 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/Stringable/ToggleTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('baz', Str::of('baz')->toggle('foo', 'bar')->get()); 24 | $this->assertEquals('bar', Str::of('foo')->toggle('foo', 'bar')->get()); 25 | $this->assertEquals('foo', Str::of('bar')->toggle('foo', 'bar')->get()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/Blade/BlankTest.php: -------------------------------------------------------------------------------- 1 | 1 2 '; 25 | 26 | $this->assertEquals($php, Blade::compileString($blade)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/Blade/FilledTest.php: -------------------------------------------------------------------------------- 1 | 1 2 '; 25 | 26 | $this->assertEquals($php, Blade::compileString($blade)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.github/workflows/style.yml: -------------------------------------------------------------------------------- 1 | name: styling 2 | 3 | on: [push] 4 | 5 | jobs: 6 | style: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Checkout code 11 | uses: actions/checkout@v2 12 | 13 | - name: Run PHP CS Fixer 14 | uses: docker://oskarstark/php-cs-fixer-ga 15 | with: 16 | args: --config=.github/.php-cs-fixer.php --allow-risky=yes 17 | 18 | - name: Extract branch name 19 | shell: bash 20 | run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})" 21 | id: extract_branch 22 | 23 | - name: Commit changes 24 | uses: stefanzweifel/git-auto-commit-action@v2.3.0 25 | with: 26 | commit_message: Fix styling 27 | branch: ${{ steps.extract_branch.outputs.branch }} 28 | env: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | -------------------------------------------------------------------------------- /src/Macros/Collection/After.php: -------------------------------------------------------------------------------- 1 | search($currentItem, true); 17 | 18 | if ($currentKey === false) { 19 | return $fallback; 20 | } 21 | 22 | $currentOffset = $this->keys()->search($currentKey, true); 23 | 24 | $next = $this->slice($currentOffset, 2); 25 | 26 | if ($next->count() < 2) { 27 | return $fallback; 28 | } 29 | 30 | return $next->last(); 31 | }); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/Stringable/PossessiveTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('', Str::of('')->possessive()->get()); 24 | $this->assertEquals('Bob\'s', Str::of('Bob')->possessive()->get()); 25 | $this->assertEquals('Charles\'', Str::of('Charles')->possessive()->get()); 26 | $this->assertEquals('its', Str::of('it')->possessive()->get()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Macros/Stringable/Possessive.php: -------------------------------------------------------------------------------- 1 | __toString())) { 19 | return $this; 20 | } 21 | 22 | if (in_array($this->__toString(), $edge_cases)) { 23 | return new Stringable($this->__toString() . 's'); 24 | } 25 | 26 | return new Stringable($this->__toString() . '\'' . ( 27 | $this->__toString()[strlen($this->__toString()) - 1] !== 's' ? 's' : '' 28 | )); 29 | }); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/Stringable/InsertTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('foobar', Str::of('foo')->insert('bar', 3)->get()); 24 | $this->assertEquals('foobar', Str::of('foo')->insert('bar', 30)->get()); 25 | $this->assertEquals('barfoo', Str::of('foo')->insert('bar', 0)->get()); 26 | $this->assertEquals('fbaroo', Str::of('foo')->insert('bar', 1)->get()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/Collection/FilterMapTest.php: -------------------------------------------------------------------------------- 1 | filterMap(function($number) { 24 | $quotient = $number / 3; 25 | 26 | return is_int($quotient) ? $quotient : null; 27 | }); 28 | 29 | $this->assertEquals([1, 2], $result->values()->toArray()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Macros/Collection/EachCons.php: -------------------------------------------------------------------------------- 1 | count() - $chunkSize + 1; 17 | $result = collect(range(0, $size))->reduce(function($result, $index) use ($chunkSize, $preserveKeys) { 18 | $next = $this->slice($index, $chunkSize); 19 | 20 | return $next->count() === $chunkSize ? $result->push($preserveKeys ? $next : $next->values()) : $result; 21 | }, new Collection([])); 22 | 23 | return $preserveKeys ? $result : $result->values(); 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Macros/Collection/SimplePaginate.php: -------------------------------------------------------------------------------- 1 | slice(($page - 1) * $perPage)->take($perPage + 1); 20 | 21 | $options += [ 22 | 'path' => Paginator::resolveCurrentPath(), 23 | 'pageName' => $pageName, 24 | ]; 25 | 26 | return new Paginator($results, $perPage, $page, $options); 27 | }); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/Collection/TransformKeysTest.php: -------------------------------------------------------------------------------- 1 | assertEquals( 23 | collect([ 24 | 'A' => 'value', 25 | 'B' => 'value', 26 | 'C' => 'value', 27 | ]), 28 | collect([ 29 | 'a' => 'value', 30 | 'b' => 'value', 31 | 'c' => 'value', 32 | ])->transformKeys('strtoupper') 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Macros/Collection/GroupByModel.php: -------------------------------------------------------------------------------- 1 | valueRetriever($callback); 17 | 18 | return $this->groupBy(function($item) use ($callback) { 19 | return $callback($item)->getKey(); 20 | }, $preserveKeys)->map(function($items) use ($callback, $modelKey, $itemsKey) { 21 | return [ 22 | $modelKey => $callback($items->first()), 23 | $itemsKey => $items, 24 | ]; 25 | })->values(); 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Macros/Collection/ParallelMap.php: -------------------------------------------------------------------------------- 1 | items, $callback, $pool); 31 | 32 | return new Collection(wait($promises)); 33 | }); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/Collection/CarbonizeTest.php: -------------------------------------------------------------------------------- 1 | assertEquals( 24 | collect([ 25 | new CarbonImmutable('yesterday'), 26 | new CarbonImmutable('tomorrow'), 27 | new CarbonImmutable('2017-07-01'), 28 | ]), 29 | collect([ 30 | 'yesterday', 31 | 'tomorrow', 32 | '2017-07-01', 33 | ])->carbonize() 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/Collection/FirstOrFailTest.php: -------------------------------------------------------------------------------- 1 | firstOrFail(); 25 | 26 | $this->assertEquals(1, $result); 27 | } 28 | 29 | /** @test */ 30 | public function it_throws_exception_when_there_are_no_items() 31 | { 32 | $this->expectException(ItemNotFoundException::class); 33 | 34 | Collection::make()->firstOrFail(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Macros/Collection/Paginate.php: -------------------------------------------------------------------------------- 1 | forPage($page, $perPage)->values(); 20 | 21 | $total = $total ?: $this->count(); 22 | 23 | $options += [ 24 | 'path' => LengthAwarePaginator::resolveCurrentPath(), 25 | 'pageName' => $pageName, 26 | ]; 27 | 28 | return new LengthAwarePaginator($results, $total, $perPage, $page, $options); 29 | }); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/Collection/WithSizeTest.php: -------------------------------------------------------------------------------- 1 | assertEquals([1], Collection::withSize(1)->toArray()); 24 | $this->assertEquals([1, 2, 3], Collection::withSize(3)->toArray()); 25 | } 26 | 27 | /** @test */ 28 | public function it_can_creates_an_empty_collection_if_the_given_size_is_lower_than_one() 29 | { 30 | $this->assertCount(0, Collection::withSize(0)); 31 | $this->assertCount(0, Collection::withSize(-1)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/Collection/HeadTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(Collection::hasMacro('head')); 24 | } 25 | 26 | /** @test */ 27 | public function it_gets_the_first_item_of_the_collection() 28 | { 29 | $data = new Collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); 30 | 31 | $this->assertEquals(1, $data->head()); 32 | } 33 | 34 | /** @test */ 35 | public function it_returns_null_if_the_collection_is_empty() 36 | { 37 | $data = new Collection(); 38 | 39 | $this->assertNull($data->head()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/Collection/AtTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(2, $data->at(1)); 26 | } 27 | 28 | /** @test */ 29 | public function it_retrieves_an_item_by_negative_index() 30 | { 31 | $data = new Collection([1, 2, 3]); 32 | 33 | $this->assertEquals(3, $data->at(-1)); 34 | } 35 | 36 | /** @test */ 37 | public function it_retrieves_an_item_by_zero_index() 38 | { 39 | $data = new Collection([1, 2, 3]); 40 | 41 | $this->assertEquals(1, $data->at(0)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © Caneara and contributors 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/Collection/ToPairsTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(Collection::hasMacro('fromPairs')); 24 | } 25 | 26 | /** @test */ 27 | public function it_can_transform_a_collection_into_an_array_with_pairs() 28 | { 29 | $this->assertEquals([ 30 | ['john@example.com', 'John'], 31 | ['jane@example.com', 'Jane'], 32 | ['dave@example.com', 'Dave'], 33 | ], Collection::make([ 34 | 'john@example.com' => 'John', 35 | 'jane@example.com' => 'Jane', 36 | 'dave@example.com' => 'Dave', 37 | ])->toPairs()->toArray()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/Collection/FromPairsTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(Collection::hasMacro('fromPairs')); 24 | } 25 | 26 | /** @test */ 27 | public function it_can_transform_a_collection_into_an_associative_array() 28 | { 29 | $this->assertEquals([ 30 | 'john@example.com' => 'John', 31 | 'jane@example.com' => 'Jane', 32 | 'dave@example.com' => 'Dave', 33 | ], Collection::make([ 34 | ['john@example.com', 'John'], 35 | ['jane@example.com', 'Jane'], 36 | ['dave@example.com', 'Dave'], 37 | ])->fromPairs()->toArray()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Macros/Collection/SectionBy.php: -------------------------------------------------------------------------------- 1 | valueRetriever($key); 17 | 18 | $results = new Collection(); 19 | 20 | foreach ($this->items as $key => $value) { 21 | $sectionName = $sectionNameRetriever($value); 22 | 23 | if (! $results->last() || $results->last()->get($sectionKey) !== $sectionName) { 24 | $results->push(new Collection([ 25 | $sectionKey => $sectionName, 26 | $itemsKey => new Collection(), 27 | ])); 28 | } 29 | 30 | $results->last()->get($itemsKey)->offsetSet($preserveKeys ? $key : null, $value); 31 | } 32 | 33 | return $results; 34 | }); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "caneara/elevate", 3 | "description": "A package that provides a library of macro functions for various Laravel components.", 4 | "keywords": [ 5 | "elevate", 6 | "php", 7 | "laravel", 8 | "macro" 9 | ], 10 | "type": "library", 11 | "license": "MIT", 12 | "homepage": "https://github.com/caneara/elevate", 13 | "autoload": { 14 | "psr-4": { 15 | "Elevate\\": "src" 16 | } 17 | }, 18 | "autoload-dev": { 19 | "psr-4": { 20 | "Elevate\\Tests\\": "tests" 21 | } 22 | }, 23 | "require": { 24 | "php": "^7.4|^8.0", 25 | "amphp/parallel": "^1.4", 26 | "amphp/parallel-functions": "^0.1.3", 27 | "symfony/stopwatch": "^5.0" 28 | }, 29 | "require-dev": { 30 | "orchestra/testbench": "^6.0", 31 | "phpunit/phpunit": "^9.0" 32 | }, 33 | "extra": { 34 | "laravel": { 35 | "providers": [ 36 | "Elevate\\ServiceProvider" 37 | ] 38 | } 39 | }, 40 | "scripts": { 41 | "test": "vendor/bin/phpunit" 42 | }, 43 | "minimum-stability": "stable" 44 | } 45 | -------------------------------------------------------------------------------- /tests/RegisterTest.php: -------------------------------------------------------------------------------- 1 | boot(); 15 | 16 | $blade = '@filled($test) 1 @else 2 @endfilled'; 17 | 18 | $this->assertNotEquals($blade, Blade::compileString($blade)); 19 | } 20 | 21 | /** @test */ 22 | public function it_only_registers_the_requested_macros() 23 | { 24 | config(['elevate' => [ 25 | 'Blade' => [ 26 | 'Blank' => true, 27 | 'Filled' => false, 28 | ], 29 | ]]); 30 | 31 | (new ServiceProvider(app()))->boot(); 32 | 33 | $blank = '@blank($test) 1 @else 2 @endblank'; 34 | $filled = '@filled($test) 1 @else 2 @endfilled'; 35 | 36 | $this->assertNotEquals($blank, Blade::compileString($blank)); 37 | $this->assertEquals('@filled($test) 1 2 @endfilled', Blade::compileString($filled)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Macros/Collection/Validate.php: -------------------------------------------------------------------------------- 1 | $item]; 22 | } 23 | 24 | if (! is_array($validationRule)) { 25 | $validationRule = ['default' => $validationRule]; 26 | } 27 | 28 | return app('validator')->make($item, $validationRule)->passes(); 29 | }; 30 | } 31 | 32 | foreach ($this->items as $item) { 33 | if (! $callback($item)) { 34 | return false; 35 | } 36 | } 37 | 38 | return true; 39 | }); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Macros/Collection/Transpose.php: -------------------------------------------------------------------------------- 1 | isEmpty()) { 19 | return new Collection(); 20 | } 21 | 22 | $firstItem = $this->first(); 23 | 24 | $expectedLength = is_array($firstItem) || $firstItem instanceof Countable ? count($firstItem) : 0; 25 | 26 | array_walk($this->items, function($row) use ($expectedLength) { 27 | if ((is_array($row) || $row instanceof Countable) && count($row) !== $expectedLength) { 28 | throw new LengthException("Element's length must be equal."); 29 | } 30 | }); 31 | 32 | $items = array_map(function(...$items) { 33 | return new Collection($items); 34 | }, ...array_map(function($items) { 35 | return $this->getArrayableItems($items); 36 | }, array_values($this->items))); 37 | 38 | return new Collection($items); 39 | }); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/Stringable/SegmentTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('', Str::of('')->segment('/', 0)->get()); 24 | 25 | $this->assertEquals('foo', Str::of('foo/bar/baz')->segment('/', 0)->get()); 26 | $this->assertEquals('bar', Str::of('foo/bar/baz')->segment('/', 1)->get()); 27 | $this->assertEquals('baz', Str::of('foo/bar/baz')->segment('/', 2)->get()); 28 | 29 | $this->assertEquals('', Str::of('foo/bar/baz')->segment('/', 3)->get()); 30 | 31 | $this->assertEquals('baz', Str::of('foo/bar/baz')->segment('/', -1)->get()); 32 | $this->assertEquals('bar', Str::of('foo/bar/baz')->segment('/', -2)->get()); 33 | $this->assertEquals('foo', Str::of('foo/bar/baz')->segment('/', -3)->get()); 34 | 35 | $this->assertEquals('', Str::of('foo/bar/baz')->segment('/', -4)->get()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/Collection/PluckToArrayTest.php: -------------------------------------------------------------------------------- 1 | 1], 25 | ['id' => 2], 26 | ['id' => 3], 27 | ])->pluckToArray('id'); 28 | 29 | $expected = [1, 2, 3]; 30 | 31 | $this->assertEquals($expected, $result); 32 | 33 | $this->assertTrue(is_array($result)); 34 | } 35 | 36 | /** @test */ 37 | public function it_return_array_of_attributes_with_correct_keys() 38 | { 39 | $result = Collection::make([ 40 | ['id' => 2, 'title' => 'A'], 41 | ['id' => 3, 'title' => 'B'], 42 | ['id' => 4, 'title' => 'C'], 43 | ])->pluckToArray('title', 'id'); 44 | 45 | $expected = [2 => 'A', 3 => 'B', 4 => 'C']; 46 | 47 | $this->assertEquals($expected, $result); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | phpunit: 7 | runs-on: ${{ matrix.os }} 8 | strategy: 9 | fail-fast: true 10 | matrix: 11 | os: [ubuntu-latest] 12 | php: [8.0] 13 | laravel: [8.*] 14 | dependency-version: [prefer-stable] 15 | include: 16 | - laravel: 8.* 17 | testbench: 6.* 18 | 19 | name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.dependency-version }} - ${{ matrix.os }} 20 | 21 | steps: 22 | - name: Checkout code 23 | uses: actions/checkout@v2 24 | 25 | - name: Cache composer dependencies 26 | uses: actions/cache@v1 27 | with: 28 | path: ~/.composer/cache/files 29 | key: dependencies-laravel-${{ matrix.laravel }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }} 30 | 31 | - name: Setup PHP 32 | uses: shivammathur/setup-php@v2 33 | with: 34 | php-version: ${{ matrix.php }} 35 | extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick 36 | coverage: none 37 | 38 | - name: Run composer 39 | run: | 40 | composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update 41 | composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-suggest 42 | 43 | - name: Run tests 44 | run: vendor/bin/phpunit -------------------------------------------------------------------------------- /tests/Collection/ValidateTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(Collection::make(['foo', 'foo'])->validate(function($item) { 14 | return $item === 'foo'; 15 | })); 16 | } 17 | 18 | /** @test */ 19 | public function it_returns_false_if_a_collection_fails_validation_with_a_callback() 20 | { 21 | $this->assertFalse(Collection::make(['foo', 'bar'])->validate(function($item) { 22 | return $item === 'foo'; 23 | })); 24 | } 25 | 26 | /** @test */ 27 | public function it_returns_true_if_a_collection_passes_validation_with_a_string() 28 | { 29 | $this->assertTrue(Collection::make(['foo', 'bar'])->validate('required')); 30 | } 31 | 32 | /** @test */ 33 | public function it_returns_false_if_a_collection_fails_validation_with_a_string() 34 | { 35 | $this->assertFalse(Collection::make(['foo', ''])->validate('required')); 36 | } 37 | 38 | /** @test */ 39 | public function it_returns_true_if_a_collection_passes_validation_with_an_array() 40 | { 41 | $this->assertTrue(Collection::make([['name' => 'foo'], ['name' => 'bar']])->validate(['name' => 'required'])); 42 | } 43 | 44 | /** @test */ 45 | public function it_returns_false_if_a_collection_fails_validation_with_an_array() 46 | { 47 | $this->assertFalse(Collection::make([['name' => 'foo'], ['name' => '']])->validate(['name' => 'required'])); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Macros/Collection/SliceBefore.php: -------------------------------------------------------------------------------- 1 | isEmpty()) { 17 | return new Collection(); 18 | } 19 | 20 | if (! $preserveKeys) { 21 | $sliced = new Collection([ 22 | new Collection([$this->first()]), 23 | ]); 24 | 25 | return $this->eachCons(2)->reduce(function($sliced, $previousAndCurrent) use ($callback) { 26 | [$previousItem, $item] = $previousAndCurrent; 27 | 28 | $callback($item, $previousItem) 29 | ? $sliced->push(new Collection([$item])) 30 | : $sliced->last()->push($item); 31 | 32 | return $sliced; 33 | }, $sliced); 34 | } 35 | 36 | $sliced = new Collection([$this->take(1)]); 37 | 38 | return $this->eachCons(2, $preserveKeys)->reduce(function($sliced, $previousAndCurrent) use ($callback) { 39 | $previousItem = $previousAndCurrent->take(1); 40 | $item = $previousAndCurrent->take(-1); 41 | 42 | $itemKey = $item->keys()->first(); 43 | $valuesItem = $item->first(); 44 | $valuesPreviousItem = $previousItem->first(); 45 | 46 | $callback($valuesItem, $valuesPreviousItem) 47 | ? $sliced->push($item) 48 | : $sliced->last()->put($itemKey, $valuesItem); 49 | 50 | return $sliced; 51 | }, $sliced); 52 | }); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /tests/Collection/ExtractTest.php: -------------------------------------------------------------------------------- 1 | user = collect([ 28 | 'name' => 'Sebastian', 29 | 'company' => 'Spatie', 30 | 'role' => [ 31 | 'name' => 'Developer', 32 | ], 33 | ]); 34 | } 35 | 36 | /** @test */ 37 | public function it_provides_an_extract_macro() 38 | { 39 | $this->assertTrue(Collection::hasMacro('extract')); 40 | } 41 | 42 | /** @test */ 43 | public function it_can_extract_a_key() 44 | { 45 | $this->assertEquals(['Sebastian'], $this->user->extract('name')->toArray()); 46 | } 47 | 48 | /** @test */ 49 | public function it_can_extract_multiple_keys() 50 | { 51 | $this->assertEquals(['Sebastian', 'Spatie'], $this->user->extract('name', 'company')->toArray()); 52 | } 53 | 54 | /** @test */ 55 | public function it_can_extract_multiple_keys_with_an_array() 56 | { 57 | $this->assertEquals(['Sebastian', 'Spatie'], $this->user->extract(['name', 'company'])->toArray()); 58 | } 59 | 60 | /** @test */ 61 | public function it_can_extract_nested_keys() 62 | { 63 | $this->assertEquals(['Sebastian', 'Developer'], $this->user->extract('name', 'role.name')->toArray()); 64 | } 65 | 66 | /** @test */ 67 | public function it_extracts_null_when_a_keys_doesnt_exist() 68 | { 69 | $this->assertEquals([null, 'Sebastian'], $this->user->extract('id', 'name')->toArray()); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /tests/Collection/AfterTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(2, $data->after(1)); 26 | } 27 | 28 | /** @test */ 29 | public function it_retrieves_items_by_value_and_doesnt_reorder_them() 30 | { 31 | $data = new Collection([ 32 | 4 => 3, 33 | 2 => 1, 34 | 1 => 2, 35 | 3 => 4, 36 | ]); 37 | 38 | $this->assertEquals(1, $data->after(3)); 39 | } 40 | 41 | /** @test */ 42 | public function it_can_find_the_next_item_in_a_collection_of_strings() 43 | { 44 | $data = new Collection([ 45 | 'foo' => 'bar', 46 | 'bar' => 'foo', 47 | ]); 48 | 49 | $this->assertEquals('foo', $data->after('bar')); 50 | } 51 | 52 | /** @test */ 53 | public function it_can_find_the_next_item_based_on_a_callback() 54 | { 55 | $data = new Collection([3, 1, 2]); 56 | 57 | $result = $data->after(function($item) { 58 | return $item > 2; 59 | }); 60 | 61 | $this->assertEquals(1, $result); 62 | } 63 | 64 | /** @test */ 65 | public function it_returns_null_if_there_isnt_a_next_item() 66 | { 67 | $data = new Collection([1, 2, 3]); 68 | 69 | $this->assertNull($data->after(3)); 70 | } 71 | 72 | /** @test */ 73 | public function it_can_return_a_fallback_value_if_there_isnt_a_next_item() 74 | { 75 | $data = new Collection([1, 2, 3]); 76 | 77 | $this->assertEquals(4, $data->after(3, 4)); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /tests/Collection/BeforeTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(1, $data->before(2)); 26 | } 27 | 28 | /** @test */ 29 | public function it_retrieves_items_by_value_and_doesnt_reorder_them() 30 | { 31 | $data = new Collection([ 32 | 4 => 3, 33 | 2 => 1, 34 | 1 => 2, 35 | 3 => 4, 36 | ]); 37 | 38 | $this->assertEquals(2, $data->before(4)); 39 | } 40 | 41 | /** @test */ 42 | public function it_can_find_the_previous_item_in_a_collection_of_strings() 43 | { 44 | $data = new Collection([ 45 | 'foo' => 'bar', 46 | 'bar' => 'foo', 47 | ]); 48 | 49 | $this->assertEquals('bar', $data->before('foo')); 50 | } 51 | 52 | /** @test */ 53 | public function it_can_find_the_previous_item_based_on_a_callback() 54 | { 55 | $data = new Collection([3, 1, 2]); 56 | 57 | $result = $data->before(function($item) { 58 | return $item < 2; 59 | }); 60 | 61 | $this->assertEquals(3, $result); 62 | } 63 | 64 | /** @test */ 65 | public function it_returns_null_if_there_isnt_a_previous_item() 66 | { 67 | $data = new Collection([1, 2, 3]); 68 | 69 | $this->assertNull($data->before(1)); 70 | } 71 | 72 | /** @test */ 73 | public function it_can_return_a_fallback_value_if_there_isnt_a_previous_item() 74 | { 75 | $data = new Collection([1, 2, 3]); 76 | 77 | $this->assertEquals('The void', $data->before(1, 'The void')); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /tests/Collection/IfAnyTest.php: -------------------------------------------------------------------------------- 1 | spy = Mockery::spy(); 29 | } 30 | 31 | public function tearDown(): void 32 | { 33 | if ($container = Mockery::getContainer()) { 34 | $this->addToAssertionCount($container->mockery_getExpectationCount()); 35 | } 36 | 37 | Mockery::close(); 38 | } 39 | 40 | /** @test */ 41 | public function it_executes_the_callable_if_the_collection_isnt_empty() 42 | { 43 | Collection::make(['foo'])->ifAny(function() { 44 | $this->spy->someCall(); 45 | }); 46 | 47 | $this->spy->shouldHaveReceived('someCall')->once(); 48 | } 49 | 50 | /** @test */ 51 | public function it_pass_the_collection_in_the_callback() 52 | { 53 | $originCollection = Collection::make(['foo']); 54 | 55 | $originCollection->ifAny(function(Collection $collection) use ($originCollection) { 56 | $this->assertEquals($originCollection, $collection); 57 | }); 58 | } 59 | 60 | /** @test */ 61 | public function it_doesnt_execute_the_callable_if_the_collection_is_empty() 62 | { 63 | Collection::make()->ifAny(function() { 64 | $this->spy->someCall(); 65 | }); 66 | 67 | $this->spy->shouldNotHaveReceived('someCall'); 68 | } 69 | 70 | /** @test */ 71 | public function it_provides_a_fluent_interface() 72 | { 73 | $collection = Collection::make(); 74 | 75 | $this->assertEquals($collection, $collection->ifAny(function() { 76 | })); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /tests/Collection/IfEmptyTest.php: -------------------------------------------------------------------------------- 1 | spy = Mockery::spy(); 29 | } 30 | 31 | public function tearDown(): void 32 | { 33 | if ($container = Mockery::getContainer()) { 34 | $this->addToAssertionCount($container->mockery_getExpectationCount()); 35 | } 36 | 37 | Mockery::close(); 38 | } 39 | 40 | /** @test */ 41 | public function it_executes_the_callable_if_the_collection_is_empty() 42 | { 43 | Collection::make()->ifEmpty(function() { 44 | $this->spy->someCall(); 45 | }); 46 | 47 | $this->spy->shouldHaveReceived('someCall')->once(); 48 | } 49 | 50 | /** @test */ 51 | public function it_pass_the_collection_in_the_callback() 52 | { 53 | $originCollection = Collection::make(); 54 | 55 | $originCollection->ifEmpty(function(Collection $collection) use ($originCollection) { 56 | $this->assertEquals($originCollection, $collection); 57 | }); 58 | } 59 | 60 | /** @test */ 61 | public function it_doesnt_execute_the_callable_if_the_collection_isnt_empty() 62 | { 63 | Collection::make(['foo'])->ifEmpty(function() { 64 | $this->spy->someCall(); 65 | }); 66 | 67 | $this->spy->shouldNotHaveReceived('someCall'); 68 | } 69 | 70 | /** @test */ 71 | public function it_provides_a_fluent_interface() 72 | { 73 | $collection = Collection::make(); 74 | 75 | $this->assertEquals($collection, $collection->ifEmpty(function() { 76 | })); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /tests/Collection/SimplePaginateTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(Collection::hasMacro('simplePaginate')); 14 | } 15 | 16 | /** @test */ 17 | public function it_returns_relevant_context_information() 18 | { 19 | $p = (new Collection(['item1', 'item2', 'item3']))->simplePaginate(2, 'page', 2); 20 | 21 | $this->assertEquals(2, $p->currentPage()); 22 | $this->assertTrue($p->hasPages()); 23 | $this->assertFalse($p->hasMorePages()); 24 | $this->assertEquals([2 => 'item3'], $p->items()); 25 | $pageInfo = [ 26 | 'per_page' => 2, 27 | 'current_page' => 2, 28 | 'next_page_url' => null, 29 | 'prev_page_url' => 'http://localhost?page=1', 30 | 'first_page_url' => 'http://localhost?page=1', 31 | 'from' => 3, 32 | 'to' => 3, 33 | 'data' => [2 => 'item3'], 34 | 'path' => 'http://localhost', 35 | ]; 36 | $this->assertEquals($pageInfo, $p->toArray()); 37 | } 38 | 39 | /** @test */ 40 | public function it_removes_trailing_slashes() 41 | { 42 | $p = (new Collection($array = ['item1', 'item2', 'item3']))->simplePaginate( 43 | 2, 44 | 'page', 45 | 2, 46 | ['path' => 'http://website.com/test/'] 47 | ); 48 | $this->assertEquals('http://website.com/test?page=1', $p->previousPageUrl()); 49 | } 50 | 51 | /** @test */ 52 | public function it_generates_urls_without_trailing_slash() 53 | { 54 | $p = (new Collection($array = ['item1', 'item2', 'item3']))->simplePaginate( 55 | 2, 56 | 'page', 57 | 2, 58 | ['path' => 'http://website.com/test'] 59 | ); 60 | $this->assertEquals('http://website.com/test?page=1', $p->previousPageUrl()); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /.github/.php-cs-fixer.php: -------------------------------------------------------------------------------- 1 | notPath(dirname(__DIR__, 1) . '/bootstrap/*') 5 | ->notPath(dirname(__DIR__, 1) . '/storage/*') 6 | ->notPath(dirname(__DIR__, 1) . '/vendor') 7 | ->notPath(dirname(__DIR__, 1) . '/resources/view/mail/*') 8 | ->in([ 9 | dirname(__DIR__, 1) . '/src', 10 | dirname(__DIR__, 1) . '/tests', 11 | ]) 12 | ->name('*.php') 13 | ->notName('*.blade.php') 14 | ->ignoreDotFiles(true) 15 | ->ignoreVCS(true); 16 | 17 | return (new PhpCsFixer\Config()) 18 | ->setRules([ 19 | '@PSR2' => true, 20 | 'array_syntax' => ['syntax' => 'short'], 21 | 'ordered_imports' => ['sort_algorithm' => 'length'], 22 | 'no_unused_imports' => true, 23 | 'not_operator_with_successor_space' => true, 24 | 'trailing_comma_in_multiline' => ['elements' => ['arrays']], 25 | 'phpdoc_scalar' => true, 26 | 'unary_operator_spaces' => true, 27 | 'binary_operator_spaces' => [ 28 | 'operators' => ['=' => 'align', '=>' => 'align'], 29 | ], 30 | 'blank_line_before_statement' => [ 31 | 'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'], 32 | ], 33 | 'phpdoc_single_line_var_spacing' => true, 34 | 'phpdoc_var_without_name' => true, 35 | 'class_attributes_separation' => [ 36 | 'elements' => [ 37 | 'method' => 'one', 38 | 'property' => 'one', 39 | ], 40 | ], 41 | 'method_argument_space' => [ 42 | 'on_multiline' => 'ensure_fully_multiline', 43 | 'keep_multiple_spaces_after_comma' => true, 44 | ], 45 | 'method_chaining_indentation' => true, 46 | 'object_operator_without_whitespace' => true, 47 | 'no_superfluous_phpdoc_tags' => true, 48 | 'function_declaration' => [ 49 | 'closure_function_spacing' => 'none', 50 | ], 51 | ]) 52 | ->setFinder($finder); 53 | -------------------------------------------------------------------------------- /tests/Collection/NoneTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(Collection::make(['foo'])->none('bar')); 25 | $this->assertFalse(Collection::make(['foo'])->none('foo')); 26 | } 27 | 28 | /** @test */ 29 | public function it_can_check_if_a_key_value_pair_isnt_present_in_a_collection() 30 | { 31 | $this->assertTrue(Collection::make([['name' => 'foo']])->none('name', 'bar')); 32 | $this->assertFalse(Collection::make([['name' => 'foo']])->none('name', 'foo')); 33 | } 34 | 35 | /** @test */ 36 | public function it_can_check_if_something_isnt_present_in_a_collection_with_a_truth_test() 37 | { 38 | // Below Laravel 5.3, the callable's parameter order is `$key, $value`. 39 | 40 | if (version_compare(Application::VERSION, '5.3.0', 'lt')) { 41 | $this->assertTrue(Collection::make(['name' => 'foo'])->none(function($key, $value) { 42 | return $key === 'name' && $value === 'bar'; 43 | })); 44 | 45 | $this->assertFalse(Collection::make(['name' => 'foo'])->none(function($key, $value) { 46 | return $key === 'name' && $value === 'foo'; 47 | })); 48 | 49 | return; 50 | } 51 | 52 | // Above Laravel 5.3, the callable's parameter order is `$value, $key`. 53 | 54 | $this->assertTrue(Collection::make(['name' => 'foo'])->none(function($value, $key) { 55 | return $key === 'name' && $value === 'bar'; 56 | })); 57 | 58 | $this->assertFalse(Collection::make(['name' => 'foo'])->none(function($value, $key) { 59 | return $key === 'name' && $value === 'foo'; 60 | })); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /config/elevate.php: -------------------------------------------------------------------------------- 1 | [ 7 | 'Blank' => true, 8 | 'Filled' => true, 9 | ], 10 | 11 | // Collection 12 | 'Collection' => [ 13 | 'After' => true, 14 | 'At' => true, 15 | 'Before' => true, 16 | 'Carbonize' => true, 17 | 'ChunkBy' => true, 18 | 'CollectBy' => true, 19 | 'EachCons' => true, 20 | 'Eighth' => true, 21 | 'Extract' => true, 22 | 'Fifth' => true, 23 | 'FilterMap' => true, 24 | 'FirstOrFail' => true, 25 | 'Fourth' => true, 26 | 'FromPairs' => true, 27 | 'Glob' => true, 28 | 'GroupByModel' => true, 29 | 'Head' => true, 30 | 'IfAny' => true, 31 | 'IfEmpty' => true, 32 | 'Ninth' => true, 33 | 'None' => true, 34 | 'Paginate' => true, 35 | 'ParallelMap' => true, 36 | 'PluckToArray' => true, 37 | 'Prioritize' => true, 38 | 'Rotate' => true, 39 | 'Second' => true, 40 | 'SectionBy' => true, 41 | 'Seventh' => true, 42 | 'SimplePaginate' => true, 43 | 'Sixth' => true, 44 | 'SliceBefore' => true, 45 | 'Tail' => true, 46 | 'Tenth' => true, 47 | 'Third' => true, 48 | 'ToPairs' => true, 49 | 'Transpose' => true, 50 | 'TransformKeys' => true, 51 | 'Trim' => true, 52 | 'Validate' => true, 53 | 'WithSize' => true, 54 | ], 55 | 56 | // Stringable 57 | 'Stringable' => [ 58 | 'AppendIf' => true, 59 | 'Collapse' => true, 60 | 'Count' => true, 61 | 'Get' => true, 62 | 'Insert' => true, 63 | 'PadLeft' => true, 64 | 'PadRight' => true, 65 | 'Possessive' => true, 66 | 'PrependIf' => true, 67 | 'Segment' => true, 68 | 'ToArray' => true, 69 | 'Toggle' => true, 70 | ], 71 | 72 | ]; 73 | -------------------------------------------------------------------------------- /tests/Collection/EachConsTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(Collection::hasMacro('eachCons')); 24 | } 25 | 26 | /** @test */ 27 | public function it_can_chunk_the_collection_into_consecutive_pairs_of_values_by_a_given_chunk_size_of_two() 28 | { 29 | $collection = new Collection([1, 2, 3, 4, 5, 6, 7, 8]); 30 | 31 | $sliced = $collection->eachCons(2); 32 | 33 | $expected = [ 34 | [1, 2], 35 | [2, 3], 36 | [3, 4], 37 | [4, 5], 38 | [5, 6], 39 | [6, 7], 40 | [7, 8], 41 | ]; 42 | 43 | $this->assertEquals($expected, $sliced->toArray()); 44 | } 45 | 46 | /** @test */ 47 | public function it_can_chunk_the_collection_into_consecutive_pairs_of_values_by_a_given_chunk_size_or_greater() 48 | { 49 | $collection = new Collection([1, 2, 3, 4, 5, 6, 7, 8]); 50 | 51 | $sliced = $collection->eachCons(4); 52 | 53 | $expected = [ 54 | [1, 2, 3, 4], 55 | [2, 3, 4, 5], 56 | [3, 4, 5, 6], 57 | [4, 5, 6, 7], 58 | [5, 6, 7, 8], 59 | ]; 60 | 61 | $this->assertEquals($expected, $sliced->toArray()); 62 | } 63 | 64 | /** @test */ 65 | public function it_can_chunk_the_collection_into_consecutive_pairs_of_values_by_a_given_chunk_size_of_two_with_preserving_the_original_keys() 66 | { 67 | $collection = new Collection([1, 2, 3, 4, 5, 6, 7, 8]); 68 | 69 | $sliced = $collection->eachCons(2, true); 70 | 71 | $expected = [ 72 | [0 => 1, 1 => 2], 73 | [1 => 2, 2 => 3], 74 | [2 => 3, 3 => 4], 75 | [3 => 4, 4 => 5], 76 | [4 => 5, 5 => 6], 77 | [5 => 6, 6 => 7], 78 | [6 => 7, 7 => 8], 79 | ]; 80 | 81 | $this->assertEquals($expected, $sliced->toArray()); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /tests/Collection/RotateTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(Collection::hasMacro('rotate')); 24 | } 25 | 26 | /** @test */ 27 | public function it_can_return_empty_collection_if_given_empty_collecton() 28 | { 29 | $collection = new Collection([]); 30 | $this->assertCount(0, $collection->rotate(2)->toArray()); 31 | } 32 | 33 | /** @test */ 34 | public function it_can_return_same_collection_if_given_zero_offset() 35 | { 36 | $collection = new Collection([1, 2, 3, 4, 5, 6]); 37 | $this->assertEquals([1, 2, 3, 4, 5, 6], $collection->rotate(0)->toArray()); 38 | } 39 | 40 | /** @test */ 41 | public function it_can_rotate_the_collection_with_offset() 42 | { 43 | $collection = new Collection([1, 2, 3, 4, 5, 6]); 44 | $this->assertEquals([3, 4, 5, 6, 1, 2], $collection->rotate(2)->toArray()); 45 | } 46 | 47 | /** @test */ 48 | public function it_can_rotate_the_collection_with_negative_offset() 49 | { 50 | $collection = new Collection([1, 2, 3, 4, 5, 6]); 51 | $this->assertEquals([5, 6, 1, 2, 3, 4], $collection->rotate(-2)->toArray()); 52 | } 53 | 54 | /** @test */ 55 | public function it_can_rotate_the_collection_with_offset_with_keys() 56 | { 57 | $collection = new Collection(['first' => 1, 'second' => 2, 'third' => 3, 'fourth' => 4, 'fifth' => 5]); 58 | $this->assertEquals(['fourth' => 4, 'fifth' => 5, 'first' => 1, 'second' => 2, 'third' => 3], $collection->rotate(3)->toArray()); 59 | } 60 | 61 | /** @test */ 62 | public function it_can_rotate_the_collection_with_nagative_offset_with_keys() 63 | { 64 | $collection = new Collection(['first' => 1, 'second' => 2, 'third' => 3, 'fourth' => 4, 'fifth' => 5]); 65 | $this->assertEquals(['third' => 3, 'fourth' => 4, 'fifth' => 5, 'first' => 1, 'second' => 2], $collection->rotate(-3)->toArray()); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /tests/Collection/CollectByTest.php: -------------------------------------------------------------------------------- 1 | 'taco', 25 | 'ingredients' => [ 26 | 'cheese', 27 | 'lettuce', 28 | 'beef', 29 | 'tortilla', 30 | ], 31 | 'should_eat' => true, 32 | ]); 33 | 34 | $ingredients = $collection->collectBy('ingredients'); 35 | 36 | $this->assertTrue(is_a($ingredients, Collection::class)); 37 | 38 | $this->assertEquals([ 39 | 'cheese', 40 | 'lettuce', 41 | 'beef', 42 | 'tortilla', 43 | ], $ingredients->toArray()); 44 | } 45 | 46 | /** @test */ 47 | public function it_returns_default_when_key_is_missing() 48 | { 49 | $collection = new Collection([ 50 | 'name' => 'taco', 51 | 'ingredients' => [ 52 | 'cheese', 53 | 'lettuce', 54 | 'beef', 55 | 'tortilla', 56 | ], 57 | 'should_eat' => true, 58 | ]); 59 | 60 | $ingredients = $collection->collectBy('build_it', $collection->get('ingredients')); 61 | 62 | $this->assertEquals($collection->collectBy('ingredients'), $ingredients); 63 | } 64 | 65 | /** @test */ 66 | public function it_returns_empty_collection_when_missing_key_without_default() 67 | { 68 | $collection = new Collection([ 69 | 'name' => 'taco', 70 | 'ingredients' => [ 71 | 'cheese', 72 | 'lettuce', 73 | 'beef', 74 | 'tortilla', 75 | ], 76 | 'should_eat' => true, 77 | ]); 78 | 79 | $ingredients = $collection->collectBy('build_it'); 80 | 81 | $this->assertEquals(new Collection, $ingredients); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /tests/Collection/PrioritizeTest.php: -------------------------------------------------------------------------------- 1 | 1], 25 | ['id' => 2], 26 | ['id' => 3], 27 | ]); 28 | 29 | $prioritized = $collection->prioritize(function(array $item) { 30 | return $item['id'] === 2; 31 | }); 32 | 33 | $this->assertEquals([2, 1, 3], $prioritized->pluck('id')->toArray()); 34 | } 35 | 36 | /** @test */ 37 | public function it_moves_multiple_elements_to_the_start_of_the_collection() 38 | { 39 | $collection = Collection::make([ 40 | ['id' => 1], 41 | ['id' => 2], 42 | ['id' => 3], 43 | ['id' => 4], 44 | ]); 45 | 46 | $prioritized = $collection->prioritize(function(array $item) { 47 | return in_array($item['id'], [2, 4]); 48 | }); 49 | 50 | $this->assertEquals([2, 4, 1, 3], $prioritized->pluck('id')->toArray()); 51 | } 52 | 53 | /** @test */ 54 | public function it_keeps_keys_of_the_original_collection() 55 | { 56 | $collection = Collection::make([ 57 | [ 58 | 'mfr' => 'Apple', 59 | 'name' => 'iPhone Xs', 60 | ], 61 | [ 62 | 'mfr' => 'Google', 63 | 'name' => 'Pixel 3', 64 | ], 65 | [ 66 | 'mfr' => 'Microsoft', 67 | 'name' => 'Lumia 950', 68 | ], 69 | [ 70 | 'mfr' => 'OnePlus', 71 | 'name' => '6T', 72 | ], 73 | [ 74 | 'mfr' => 'Samsung', 75 | 'name' => 'Galaxy S9', 76 | ], 77 | ])->keyBy('mfr'); 78 | 79 | $prioritized = $collection->prioritize(function($phones, $mfr) { 80 | return in_array($mfr, ['OnePlus', 'Samsung']); 81 | }); 82 | $this->assertEquals(['OnePlus', 'Samsung', 'Apple', 'Google', 'Microsoft'], $prioritized->keys()->toArray()); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /tests/Collection/TailTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(Collection::hasMacro('tail')); 24 | } 25 | 26 | /** @test */ 27 | public function it_can_tail_the_collection_with_numbers_without_preserving_the_keys() 28 | { 29 | $collection = new Collection([10, 34, 51, 17, 47, 64, 9, 44, 20, 59, 66, 77]); 30 | 31 | $tail = $collection->tail(); 32 | 33 | $expected = [ 34 | 34, 35 | 51, 36 | 17, 37 | 47, 38 | 64, 39 | 9, 40 | 44, 41 | 20, 42 | 59, 43 | 66, 44 | 77, 45 | ]; 46 | 47 | $this->assertEquals($expected, $tail->toArray()); 48 | } 49 | 50 | /** @test */ 51 | public function it_can_tail_the_collection_with_strings_without_preserving_the_keys() 52 | { 53 | $collection = new Collection(['1', '2', '3', 'Hello', 'Spatie']); 54 | 55 | $tail = $collection->tail(); 56 | 57 | $expected = [ 58 | '2', 59 | '3', 60 | 'Hello', 61 | 'Spatie', 62 | ]; 63 | 64 | $this->assertEquals($expected, $tail->toArray()); 65 | } 66 | 67 | /** @test */ 68 | public function it_can_tail_the_collection_with_numbers_with_preserving_the_keys() 69 | { 70 | $collection = new Collection([10, 34, 51, 17, 47, 64, 9, 44, 20, 59, 66, 77]); 71 | 72 | $tail = $collection->tail(true); 73 | 74 | $expected = [ 75 | 1 => 34, 76 | 2 => 51, 77 | 3 => 17, 78 | 4 => 47, 79 | 5 => 64, 80 | 6 => 9, 81 | 7 => 44, 82 | 8 => 20, 83 | 9 => 59, 84 | 10 => 66, 85 | 11 => 77, 86 | ]; 87 | 88 | $this->assertEquals($expected, $tail->toArray()); 89 | } 90 | 91 | /** @test */ 92 | public function it_can_tail_the_collection_with_strings() 93 | { 94 | $collection = new Collection(['1', '2', '3', 'Hello', 'Spatie']); 95 | 96 | $tail = $collection->tail(true); 97 | 98 | $expected = [ 99 | 1 => '2', 100 | 2 => '3', 101 | 3 => 'Hello', 102 | 4 => 'Spatie', 103 | ]; 104 | 105 | $this->assertEquals($expected, $tail->toArray()); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /tests/Collection/PaginateTest.php: -------------------------------------------------------------------------------- 1 | collectionPaginator = (new Collection(['item1', 'item2', 'item3', 'item4']))->paginate(2, 'page', 2, null); 25 | } 26 | 27 | /** @test */ 28 | public function it_provides_paginate_macro() 29 | { 30 | $this->assertTrue(Collection::hasMacro('paginate')); 31 | } 32 | 33 | /** @test */ 34 | public function it_gives_correct_total_number() 35 | { 36 | $this->assertEquals(4, $this->collectionPaginator->total()); 37 | } 38 | 39 | /** @test */ 40 | public function it_gets_and_sets_page_name() 41 | { 42 | $this->collectionPaginator = (new Collection(range(0, 22)))->paginate(); 43 | $this->assertEquals('page', $this->collectionPaginator->getPageName()); 44 | $this->collectionPaginator->setPageName('p'); 45 | $this->assertEquals('p', $this->collectionPaginator->getPageName()); 46 | } 47 | 48 | /** @test */ 49 | public function it_can_generate_urls() 50 | { 51 | $this->collectionPaginator->setPath('http://website.com'); 52 | $this->collectionPaginator->setPageName('foo'); 53 | $this->assertEquals( 54 | 'http://website.com?foo=2', 55 | $this->collectionPaginator->url($this->collectionPaginator->currentPage()) 56 | ); 57 | $this->assertEquals( 58 | 'http://website.com?foo=1', 59 | $this->collectionPaginator->url($this->collectionPaginator->currentPage() - 1) 60 | ); 61 | $this->assertEquals( 62 | 'http://website.com?foo=1', 63 | $this->collectionPaginator->url($this->collectionPaginator->currentPage() - 2) 64 | ); 65 | } 66 | 67 | public function it_can_generate_urls_with_query() 68 | { 69 | $this->collectionPaginator->setPath('http://website.com?sort_by=date'); 70 | $this->collectionPaginator->setPageName('foo'); 71 | $this->assertEquals( 72 | 'http://website.com?sort_by=date&foo=2', 73 | $this->collectionPaginator->url($this->collectionPaginator->currentPage()) 74 | ); 75 | } 76 | 77 | public function it_can_generate_urls_without_trailing_slashes() 78 | { 79 | $this->collectionPaginator->setPath('http://website.com/test'); 80 | $this->collectionPaginator->setPageName('foo'); 81 | $this->assertEquals( 82 | 'http://website.com/test?foo=2', 83 | $this->collectionPaginator->url($this->collectionPaginator->currentPage()) 84 | ); 85 | $this->assertEquals( 86 | 'http://website.com/test?foo=1', 87 | $this->collectionPaginator->url($this->collectionPaginator->currentPage() - 1) 88 | ); 89 | $this->assertEquals( 90 | 'http://website.com/test?foo=1', 91 | $this->collectionPaginator->url($this->collectionPaginator->currentPage() - 2) 92 | ); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /tests/Collection/ChunkByTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(Collection::hasMacro('chunkBy')); 24 | } 25 | 26 | /** @test */ 27 | public function it_can_chunk_the_collection_with_a_given_callback() 28 | { 29 | $collection = new Collection(['A', 'A', 'A', 'B', 'B', 'A', 'A', 'C', 'B', 'B', 'A']); 30 | 31 | $chunkedBy = $collection->chunkBy(function($item) { 32 | return $item == 'A'; 33 | }); 34 | 35 | $expected = [ 36 | ['A', 'A', 'A'], 37 | ['B', 'B'], 38 | ['A', 'A'], 39 | ['C', 'B', 'B'], 40 | ['A'], 41 | ]; 42 | 43 | $this->assertEquals($expected, $chunkedBy->toArray()); 44 | } 45 | 46 | /** @test */ 47 | public function it_can_chunk_the_collection_with_a_given_callback_with_associative_keys() 48 | { 49 | $collection = new Collection(['a' => 'A', 'b' => 'A', 'c' => 'A', 'd' => 'B', 'e' => 'B', 'f' => 'A', 'g' => 'A', 'h' => 'C', 'i' => 'B', 'j' => 'B', 'k' => 'A']); 50 | 51 | $chunkedBy = $collection->chunkBy(function($item) { 52 | return $item == 'A'; 53 | }); 54 | 55 | $expected = [ 56 | ['A', 'A', 'A'], 57 | ['B', 'B'], 58 | ['A', 'A'], 59 | ['C', 'B', 'B'], 60 | ['A'], 61 | ]; 62 | 63 | $this->assertEquals($expected, $chunkedBy->toArray()); 64 | } 65 | 66 | /** @test */ 67 | public function it_can_chunk_the_collection_with_a_given_callback_and_preserve_the_original_keys() 68 | { 69 | $collection = new Collection(['A', 'A', 'A', 'B', 'B', 'A', 'A', 'C', 'B', 'B', 'A']); 70 | 71 | $chunkedBy = $collection->chunkBy(function($item) { 72 | return $item == 'A'; 73 | }, true); 74 | 75 | $expected = [ 76 | [0 => 'A', 1 => 'A', 2 => 'A'], 77 | [3 => 'B', 4 => 'B'], 78 | [5 => 'A', 6 => 'A'], 79 | [7 => 'C', 8 => 'B', 9 => 'B'], 80 | [10 => 'A'], 81 | ]; 82 | 83 | $this->assertEquals($expected, $chunkedBy->toArray()); 84 | } 85 | 86 | /** @test */ 87 | public function it_can_chunk_the_collection_with_a_given_callback_with_associative_keys_and_preserve_the_original_keys() 88 | { 89 | $collection = new Collection(['a' => 'A', 'b' => 'A', 'c' => 'A', 'd' => 'B', 'e' => 'B', 'f' => 'A', 'g' => 'A', 'h' => 'C', 'i' => 'B', 'j' => 'B', 'k' => 'A']); 90 | 91 | $chunkedBy = $collection->chunkBy(function($item) { 92 | return $item == 'A'; 93 | }, true); 94 | 95 | $expected = [ 96 | ['a' => 'A', 'b' => 'A', 'c' => 'A'], 97 | ['d' => 'B', 'e' => 'B'], 98 | ['f' => 'A', 'g' => 'A'], 99 | ['h' => 'C', 'i' => 'B', 'j' => 'B'], 100 | ['k' => 'A'], 101 | ]; 102 | 103 | $this->assertEquals($expected, $chunkedBy->toArray()); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /tests/Collection/GetHumanCountTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(1, $data->first()); 26 | } 27 | 28 | /** @test */ 29 | public function it_gets_the_second_item_of_the_collection() 30 | { 31 | $data = new Collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); 32 | 33 | $this->assertEquals(2, $data->second()); 34 | } 35 | 36 | /** @test */ 37 | public function it_gets_the_third_item_of_the_collection() 38 | { 39 | $data = new Collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); 40 | 41 | $this->assertEquals(3, $data->third()); 42 | } 43 | 44 | /** @test */ 45 | public function it_gets_the_fourth_item_of_the_collection() 46 | { 47 | $data = new Collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); 48 | 49 | $this->assertEquals(4, $data->fourth()); 50 | } 51 | 52 | /** @test */ 53 | public function it_gets_the_fifth_item_of_the_collection() 54 | { 55 | $data = new Collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); 56 | 57 | $this->assertEquals(5, $data->fifth()); 58 | } 59 | 60 | /** @test */ 61 | public function it_gets_the_sixth_item_of_the_collection() 62 | { 63 | $data = new Collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); 64 | 65 | $this->assertEquals(6, $data->sixth()); 66 | } 67 | 68 | /** @test */ 69 | public function it_gets_the_seventh_item_of_the_collection() 70 | { 71 | $data = new Collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); 72 | 73 | $this->assertEquals(7, $data->seventh()); 74 | } 75 | 76 | /** @test */ 77 | public function it_gets_the_eighth_item_of_the_collection() 78 | { 79 | $data = new Collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); 80 | 81 | $this->assertEquals(8, $data->eighth()); 82 | } 83 | 84 | /** @test */ 85 | public function it_gets_the_ninth_item_of_the_collection() 86 | { 87 | $data = new Collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); 88 | 89 | $this->assertEquals(9, $data->ninth()); 90 | } 91 | 92 | /** @test */ 93 | public function it_gets_the_tenth_item_of_the_collection() 94 | { 95 | $data = new Collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); 96 | 97 | $this->assertEquals(10, $data->tenth()); 98 | } 99 | 100 | /** @test */ 101 | public function it_returns_null_if_index_is_undefined() 102 | { 103 | $data = new Collection(); 104 | 105 | $this->assertNull($data->first()); 106 | $this->assertNull($data->second()); 107 | $this->assertNull($data->third()); 108 | $this->assertNull($data->fourth()); 109 | $this->assertNull($data->fifth()); 110 | $this->assertNull($data->sixth()); 111 | $this->assertNull($data->seventh()); 112 | $this->assertNull($data->eighth()); 113 | $this->assertNull($data->ninth()); 114 | $this->assertNull($data->tenth()); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /tests/Collection/SectionByTest.php: -------------------------------------------------------------------------------- 1 | 'Lesson 1', 'module' => 'Basics'], 26 | ['name' => 'Lesson 2', 'module' => 'Basics'], 27 | ]], 28 | ['Advanced', [ 29 | ['name' => 'Lesson 3', 'module' => 'Advanced'], 30 | ['name' => 'Lesson 4', 'module' => 'Advanced'], 31 | ]], 32 | ['Basics', [ 33 | ['name' => 'Lesson 5', 'module' => 'Basics'], 34 | ]], 35 | ]; 36 | 37 | $sections = $this->getDummyCollection()->sectionBy('module'); 38 | 39 | $this->assertCount(3, $sections); 40 | 41 | foreach ($expected as $i => $section) { 42 | $this->assertEquals($section[0], $sections[$i][0]); 43 | $this->assertEquals($section[1], $sections[$i][1]->toArray()); 44 | } 45 | } 46 | 47 | /** @test */ 48 | public function it_can_use_custom_keys_for_the_section_and_items() 49 | { 50 | $collection = $this->getDummyCollection(); 51 | 52 | $sectioned = $collection->sectionBy('module', false, 'section', 'items'); 53 | 54 | $expected = [ 55 | [ 56 | 'section' => 'Basics', 57 | 'items' => [ 58 | ['name' => 'Lesson 1', 'module' => 'Basics'], 59 | ['name' => 'Lesson 2', 'module' => 'Basics'], 60 | ], 61 | ], 62 | [ 63 | 'section' => 'Advanced', 64 | 'items' => [ 65 | ['name' => 'Lesson 3', 'module' => 'Advanced'], 66 | ['name' => 'Lesson 4', 'module' => 'Advanced'], 67 | ], 68 | ], 69 | [ 70 | 'section' => 'Basics', 71 | 'items' => [ 72 | ['name' => 'Lesson 5', 'module' => 'Basics'], 73 | ], 74 | ], 75 | ]; 76 | 77 | $this->assertEquals($expected, $sectioned->map(function($section) { 78 | $section['items'] = $section['items']->toArray(); 79 | 80 | return $section; 81 | })->toArray()); 82 | } 83 | 84 | /** @test */ 85 | public function it_can_preserve_keys() 86 | { 87 | $collection = $this->getDummyCollection(); 88 | 89 | $sectioned = $collection->sectionBy('module', true, 'module', 'items'); 90 | 91 | $expected = [ 92 | [ 93 | 'module' => 'Basics', 94 | 'items' => [ 95 | 'lesson1' => ['name' => 'Lesson 1', 'module' => 'Basics'], 96 | 'lesson2' => ['name' => 'Lesson 2', 'module' => 'Basics'], 97 | ], 98 | ], 99 | [ 100 | 'module' => 'Advanced', 101 | 'items' => [ 102 | 'lesson3' => ['name' => 'Lesson 3', 'module' => 'Advanced'], 103 | 'lesson4' => ['name' => 'Lesson 4', 'module' => 'Advanced'], 104 | ], 105 | ], 106 | [ 107 | 'module' => 'Basics', 108 | 'items' => [ 109 | 'lesson5' => ['name' => 'Lesson 5', 'module' => 'Basics'], 110 | ], 111 | ], 112 | ]; 113 | 114 | $this->assertEquals($expected, $sectioned->map(function($section) { 115 | $section['items'] = $section['items']->toArray(); 116 | 117 | return $section; 118 | })->toArray()); 119 | } 120 | 121 | protected function getDummyCollection(): Collection 122 | { 123 | return Collection::make([ 124 | 'lesson1' => ['name' => 'Lesson 1', 'module' => 'Basics'], 125 | 'lesson2' => ['name' => 'Lesson 2', 'module' => 'Basics'], 126 | 'lesson3' => ['name' => 'Lesson 3', 'module' => 'Advanced'], 127 | 'lesson4' => ['name' => 'Lesson 4', 'module' => 'Advanced'], 128 | 'lesson5' => ['name' => 'Lesson 5', 'module' => 'Basics'], 129 | ]); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /tests/Collection/SliceBeforeTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(Collection::hasMacro('sliceBefore')); 24 | } 25 | 26 | /** @test */ 27 | public function it_can_slice_before_the_collection_with_a_given_callback() 28 | { 29 | $collection = new Collection([10, 34, 51, 17, 47, 64, 9, 44, 20, 59, 66, 77]); 30 | 31 | $sliced = $collection->sliceBefore(function($number) { 32 | return $number > 50; 33 | }); 34 | 35 | $expected = [ 36 | [10, 34], 37 | [51, 17, 47], 38 | [64, 9, 44, 20], 39 | [59], 40 | [66], 41 | [77], 42 | ]; 43 | 44 | $this->assertEquals($expected, $sliced->toArray()); 45 | } 46 | 47 | /** @test */ 48 | public function it_can_slice_before_the_collection_with_a_given_callback_with_preserving_the_original_keys() 49 | { 50 | $collection = new Collection([10, 34, 51, 17, 47, 64, 9, 44, 20, 59, 66, 77]); 51 | 52 | $sliced = $collection->sliceBefore(function($number) { 53 | return $number > 50; 54 | }, true); 55 | 56 | $expected = [ 57 | [0 => 10, 1 => 34], 58 | [2 => 51, 3 => 17, 4 => 47], 59 | [5 => 64, 6 => 9, 7 => 44, 8 => 20], 60 | [9 => 59], 61 | [10 => 66], 62 | [11 => 77], 63 | ]; 64 | 65 | $toArray = $sliced->toArray(); 66 | $this->assertEquals($expected, $toArray); 67 | } 68 | 69 | /** @test */ 70 | public function it_can_slice_before_the_collection_with_complex_data_with_a_given_callback_without_preserving_the_original_keys() 71 | { 72 | $collection = new Collection([10, [34, 51], [17], 47, [64, 9], 44, [20], [59], [66], 77]); 73 | 74 | $sliced = $collection->sliceBefore(function($item) { 75 | return is_array($item); 76 | }); 77 | 78 | $expected = [ 79 | [10], 80 | [[34, 51]], 81 | [[17], 47], 82 | [[64, 9], 44], 83 | [[20]], 84 | [[59]], 85 | [[66], 77], 86 | ]; 87 | 88 | $this->assertEquals($expected, $sliced->toArray()); 89 | } 90 | 91 | /** @test */ 92 | public function it_can_slice_before_the_collection_with_complex_data_with_a_given_callback_with_preserving_the_original_keys() 93 | { 94 | $collection = new Collection([10, [34, 51], [17], 47, [64, 9], 44, [20], [59], [66], 77]); 95 | 96 | $sliced = $collection->sliceBefore(function($item) { 97 | return is_array($item); 98 | }, true); 99 | 100 | $expected = [ 101 | [0 => 10], 102 | [1 => [34, 51]], 103 | [2 => [17], 3 => 47], 104 | [4 => [64, 9], 5 => 44], 105 | [6 => [20]], 106 | [7 => [59]], 107 | [8 => [66], 9 => 77], 108 | ]; 109 | 110 | $this->assertEquals($expected, $sliced->toArray()); 111 | } 112 | 113 | /** @test */ 114 | public function it_can_slice_before_the_collection_with_a_given_callback_without_preserving_the_original_associative_keys() 115 | { 116 | $collection = new Collection(['a' => 10, 'b' => 34, 'c' => 51, 'd' => 17, 'e' => 47, 'f' => 64, 'g' => 9, 'h' => 44, 'i' => 20, 'j' => 59, 'k' => 66, 'l' => 77]); 117 | 118 | $sliced = $collection->sliceBefore(function($number) { 119 | return $number > 50; 120 | }); 121 | 122 | $expected = [ 123 | [10, 34], 124 | [51, 17, 47], 125 | [64, 9, 44, 20], 126 | [59], 127 | [66], 128 | [77], 129 | ]; 130 | 131 | $this->assertEquals($expected, $sliced->toArray()); 132 | } 133 | 134 | /** @test */ 135 | public function it_can_slice_before_the_collection_with_a_given_callback_with_preserving_the_original_associative_keys() 136 | { 137 | $collection = new Collection(['a' => 10, 'b' => 34, 'c' => 51, 'd' => 17, 'e' => 47, 'f' => 64, 'g' => 9, 'h' => 44, 'i' => 20, 'j' => 59, 'k' => 66, 'l' => 77]); 138 | 139 | $sliced = $collection->sliceBefore(function($number) { 140 | return $number > 50; 141 | }, true); 142 | 143 | $expected = [ 144 | ['a' => 10, 'b' => 34], 145 | ['c' => 51, 'd' => 17, 'e' => 47], 146 | ['f' => 64, 'g' => 9, 'h' => 44, 'i' => 20], 147 | ['j' => 59], 148 | ['k' => 66], 149 | ['l' => 77], 150 | ]; 151 | 152 | $this->assertEquals($expected, $sliced->toArray()); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /tests/Collection/TransposeTest.php: -------------------------------------------------------------------------------- 1 | [ 26 | new Collection(), 27 | new Collection(), 28 | ], 29 | 'single-element' => [ 30 | new Collection([ 31 | ['11'], 32 | ]), 33 | new Collection([ 34 | new Collection(['11']), 35 | ]), 36 | ], 37 | 'single-row' => [ 38 | new Collection([ 39 | ['11', '12', '13'], 40 | ]), 41 | new Collection([ 42 | new Collection(['11']), 43 | new Collection(['12']), 44 | new Collection(['13']), 45 | ]), 46 | ], 47 | 'single-column' => [ 48 | new Collection([ 49 | ['11'], 50 | ['12'], 51 | ['13'], 52 | ]), 53 | new Collection([ 54 | new Collection(['11', '12', '13']), 55 | ]), 56 | ], 57 | 'tall-rect' => [ 58 | new Collection([ 59 | ['11', '12'], 60 | ['21', '22'], 61 | ['31', '32'], 62 | ]), 63 | new Collection([ 64 | new Collection(['11', '21', '31']), 65 | new Collection(['12', '22', '32']), 66 | ]), 67 | ], 68 | 'wide-rect' => [ 69 | new Collection([ 70 | ['11', '12', '13'], 71 | ['21', '22', '23'], 72 | ]), 73 | new Collection([ 74 | new Collection(['11', '21']), 75 | new Collection(['12', '22']), 76 | new Collection(['13', '23']), 77 | ]), 78 | ], 79 | 'square' => [ 80 | new Collection([ 81 | ['11', '12', '13'], 82 | ['21', '22', '23'], 83 | ['31', '32', '33'], 84 | ]), 85 | new Collection([ 86 | new Collection(['11', '21', '31']), 87 | new Collection(['12', '22', '32']), 88 | new Collection(['13', '23', '33']), 89 | ]), 90 | ], 91 | 'arrayable' => [ 92 | new Collection([ 93 | ['11', '12', '13'], 94 | new ArrayObject(['21', '22', '23']), 95 | new Collection(['31', '32', '33']), 96 | ]), 97 | new Collection([ 98 | new Collection(['11', '21', '31']), 99 | new Collection(['12', '22', '32']), 100 | new Collection(['13', '23', '33']), 101 | ]), 102 | ], 103 | ]; 104 | } 105 | 106 | /** 107 | * @test 108 | * @dataProvider transposableCollections 109 | */ 110 | public function it_can_transpose_an_array(Collection $collection, Collection $expected) 111 | { 112 | $this->assertEquals($expected, $collection->transpose()); 113 | } 114 | 115 | /** @test */ 116 | public function it_will_enforce_length_equality() 117 | { 118 | $this->expectException(LengthException::class); 119 | $this->expectExceptionMessage("Element's length must be equal."); 120 | 121 | $collection = new Collection([ 122 | ['11', '12', '13'], 123 | ['21', '22'], 124 | ['31', '32', '33'], 125 | ]); 126 | 127 | $collection->transpose(); 128 | } 129 | 130 | /** @test */ 131 | public function it_will_remove_existing_keys() 132 | { 133 | $collection = new Collection([ 134 | 'one' => ['11', '12', '13'], 135 | 'two' => ['21', '22', '23'], 136 | 'three' => ['31', '32', '33'], 137 | ]); 138 | 139 | $expected = new Collection([ 140 | new Collection(['11', '21', '31']), 141 | new Collection(['12', '22', '32']), 142 | new Collection(['13', '23', '33']), 143 | ]); 144 | 145 | $this->assertEquals($expected, $collection->transpose()); 146 | } 147 | 148 | /** @test */ 149 | public function it_can_transpose_a_single_row_array() 150 | { 151 | $collection = new Collection([ 152 | ['11', '12', '13'], 153 | ]); 154 | 155 | $expected = new Collection([ 156 | new Collection(['11']), 157 | new Collection(['12']), 158 | new Collection(['13']), 159 | ]); 160 | 161 | $this->assertEquals($expected, $collection->transpose()); 162 | } 163 | 164 | /** @test */ 165 | public function it_can_handle_null_values() 166 | { 167 | $collection = new Collection([ 168 | null, 169 | ]); 170 | 171 | $expected = new Collection(); 172 | 173 | $this->assertEquals($expected, $collection->transpose()); 174 | } 175 | 176 | /** @test */ 177 | public function it_can_handle_collections_values() 178 | { 179 | $collection = new Collection([ 180 | new Collection([1, 2, 3]), 181 | ]); 182 | 183 | $expected = new Collection([ 184 | new Collection([1]), 185 | new Collection([2]), 186 | new Collection([3]), 187 | ]); 188 | 189 | $this->assertEquals($expected, $collection->transpose()); 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /tests/Collection/GroupByModelTest.php: -------------------------------------------------------------------------------- 1 | getDummies(); 26 | 27 | $expected = [ 28 | [$model1, [ 29 | ['model' => $model1, 'foo' => 'bar'], 30 | ['model' => $model1, 'foo' => 'baz'], 31 | ]], 32 | [$model2, [ 33 | ['model' => $model2, 'foo' => 'qux'], 34 | ]], 35 | ]; 36 | 37 | $grouped = $collection->groupByModel(function($item) { 38 | return $item['model']; 39 | }); 40 | 41 | $this->assertCount(2, $grouped); 42 | 43 | foreach ($expected as $i => $group) { 44 | $this->assertEquals($group[0], $grouped[$i][0]); 45 | $this->assertEquals($group[1], $grouped[$i][1]->toArray()); 46 | } 47 | } 48 | 49 | /** @test */ 50 | public function it_can_group_a_collection_by_a_model_with_a_callable_and_custom_key_names() 51 | { 52 | [$model1, $model2, $collection] = $this->getDummies(); 53 | 54 | $grouped = $collection->groupByModel(function($item) { 55 | return $item['model']; 56 | }, false, 'myKey', 'items'); 57 | 58 | $expected = [ 59 | [ 60 | 'myKey' => $model1, 61 | 'items' => [ 62 | ['model' => $model1, 'foo' => 'bar'], 63 | ['model' => $model1, 'foo' => 'baz'], 64 | ], 65 | ], 66 | [ 67 | 'myKey' => $model2, 68 | 'items' => [ 69 | ['model' => $model2, 'foo' => 'qux'], 70 | ], 71 | ], 72 | ]; 73 | 74 | $this->assertEquals($expected, $grouped->map(function($group) { 75 | $group['items'] = $group['items']->toArray(); 76 | 77 | return $group; 78 | })->toArray()); 79 | } 80 | 81 | /** @test */ 82 | public function it_can_group_a_collection_by_a_model_with_a_key() 83 | { 84 | [$model1, $model2, $collection] = $this->getDummies(); 85 | 86 | $grouped = $collection->groupByModel('model'); 87 | 88 | $expected = [ 89 | [$model1, [ 90 | ['model' => $model1, 'foo' => 'bar'], 91 | ['model' => $model1, 'foo' => 'baz'], 92 | ]], 93 | [$model2, [ 94 | ['model' => $model2, 'foo' => 'qux'], 95 | ]], 96 | ]; 97 | 98 | $this->assertCount(2, $grouped); 99 | 100 | foreach ($expected as $i => $group) { 101 | $this->assertEquals($group[0], $grouped[$i][0]); 102 | $this->assertEquals($group[1], $grouped[$i][1]->toArray()); 103 | } 104 | } 105 | 106 | /** @test */ 107 | public function it_can_group_a_collection_by_a_model_with_a_key_and_custom_key_names() 108 | { 109 | [$model1, $model2, $collection] = $this->getDummies(); 110 | 111 | $grouped = $collection->groupByModel('model', false, 'myKey', 'items'); 112 | 113 | $expected = [ 114 | [ 115 | 'myKey' => $model1, 116 | 'items' => [ 117 | ['model' => $model1, 'foo' => 'bar'], 118 | ['model' => $model1, 'foo' => 'baz'], 119 | ], 120 | ], 121 | [ 122 | 'myKey' => $model2, 123 | 'items' => [ 124 | ['model' => $model2, 'foo' => 'qux'], 125 | ], 126 | ], 127 | ]; 128 | 129 | $this->assertEquals($expected, $grouped->map(function($group) { 130 | $group['items'] = $group['items']->toArray(); 131 | 132 | return $group; 133 | })->toArray()); 134 | } 135 | 136 | /** @test */ 137 | public function it_can_group_a_collection_by_a_model_with_a_key_and_a_custom_items_key() 138 | { 139 | [$model1, $model2, $collection] = $this->getDummies(); 140 | 141 | $grouped = $collection->groupByModel('model', false, 'model', 'myItems'); 142 | 143 | $expected = [ 144 | [ 145 | 'model' => $model1, 146 | 'myItems' => [ 147 | ['model' => $model1, 'foo' => 'bar'], 148 | ['model' => $model1, 'foo' => 'baz'], 149 | ], 150 | ], 151 | [ 152 | 'model' => $model2, 153 | 'myItems' => [ 154 | ['model' => $model2, 'foo' => 'qux'], 155 | ], 156 | ], 157 | ]; 158 | 159 | $this->assertEquals($expected, $grouped->map(function($group) { 160 | $group['myItems'] = $group['myItems']->toArray(); 161 | 162 | return $group; 163 | })->toArray()); 164 | } 165 | 166 | /** @test */ 167 | public function it_can_group_a_collection_by_a_model_and_preserve_keys() 168 | { 169 | [$model1, $model2, $collection] = $this->getDummies(); 170 | 171 | $grouped = $collection->groupByModel('model', true, 'model', 'items'); 172 | 173 | $expected = [ 174 | [ 175 | 'model' => $model1, 176 | 'items' => [ 177 | 'dummy1' => ['model' => $model1, 'foo' => 'bar'], 178 | 'dummy2' => ['model' => $model1, 'foo' => 'baz'], 179 | ], 180 | ], 181 | [ 182 | 'model' => $model2, 183 | 'items' => [ 184 | 'dummy3' => ['model' => $model2, 'foo' => 'qux'], 185 | ], 186 | ], 187 | ]; 188 | 189 | $this->assertEquals($expected, $grouped->map(function($group) { 190 | $group['items'] = $group['items']->toArray(); 191 | 192 | return $group; 193 | })->toArray()); 194 | } 195 | 196 | protected function getDummies(): array 197 | { 198 | $model1 = Mockery::mock(Model::class); 199 | $model1->shouldReceive('getKey')->andReturn(1); 200 | 201 | $model2 = Mockery::mock(Model::class); 202 | $model2->shouldReceive('getKey')->andReturn(2); 203 | 204 | $collection = Collection::make([ 205 | 'dummy1' => ['model' => $model1, 'foo' => 'bar'], 206 | 'dummy2' => ['model' => $model1, 'foo' => 'baz'], 207 | 'dummy3' => ['model' => $model2, 'foo' => 'qux'], 208 | ]); 209 | 210 | return [$model1, $model2, $collection]; 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Elevate 2 | 3 | This package provides a library of macro functions for various Laravel components. Use them to augment the existing functionality offered by the likes of Blade, Collections, Stringable, and so on. 4 | 5 | Initially, only a handful of macros are available. That said, the library has been designed so that it can handle dozens or even hundreds of macros being added over time. Each individual macro may also be disabled, thus ensuring that Laravel isn't spending precious time registering macros you are not using. 6 | 7 | ## Installation 8 | 9 | Pull in the package using composer 10 | 11 | ```bash 12 | composer require caneara/elevate 13 | ``` 14 | 15 | ## Configuration 16 | 17 | If you wish to make all of the macros available to your application, then you can skip this section. Otherwise, you should publish the configuration file using Artisan: 18 | 19 | ```bash 20 | php artisan vendor:publish --provider="Elevate\ServiceProvider" 21 | ``` 22 | 23 | You may wish to disable a particular macro for one of the following reasons: 24 | 25 | 1. **Performance** - if you aren't using the macro, or even the class itself, then disabling it will net a tiny performance boost. 26 | 2. **Conflicts** - if you already have a macro for a class, or wish to create one with the same name, you should disable the Elevate macro to prevent conflicts. 27 | 28 | To prevent a macro being registered, simply set its value to `false`: 29 | 30 | ```php 31 | 'Blade' => [ 32 | 'Blank' => true, 33 | 'Filled' => false, 34 | ]; 35 | ``` 36 | 37 | ## Available macros 38 | 39 | The following macros are currently available: 40 | 41 | | Macro | Class | Description 42 | | -------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- 43 | | filled | Blade | Enables the use of @filled() and @endfilled. Uses the filled() global helper under the hood. You may also use @else e.g. @filled() @else @endfilled 44 | | blank | Blade | Enables the use of @blank() and @endblank. Uses the blank() global helper under the hood. You may also use @else e.g. @blank() @else @endblank 45 | | appendIf | Stringable | Appends the given string to the string if it doesn't already finish with it 46 | | collapse | Stringable | Trims the string and replaces multiple whitespace characters with a single space 47 | | count | Stringable | Determine the total number of times the given string appears within the string 48 | | get | Stringable | Adds a more friendly helper to access a fluent string's content e.g. Str::of('test')->get() 49 | | insert | Stringable | Injects the given string at the given index 50 | | padLeft | Stringable | Pad the string to the given length from the left side 51 | | padRight | Stringable | Pad the string to the given length from the right side 52 | | possessive | Stringable | Converts the string to a possessive version e.g. Bob -> Bob's 53 | | prependIf | Stringable | Prepends the given string to the string if it doesn't already start with it 54 | | segment | Stringable | Splits the string using the given delimiter, then retrieves the item at the given array index 55 | | toArray | Stringable | Converts the string into an array of characters 56 | | toggle | Stringable | Toggles the string between two states. Contains a $loose flag to allow the switching of a string that matches neither states 57 | | after | Collection | Get the next item from the collection 58 | | at | Collection | Retrieve an item at an index 59 | | second | Collection | Retrieve item at the second index 60 | | third | Collection | Retrieve item at the third index 61 | | fourth | Collection | Retrieve item at the fourth index 62 | | fifth | Collection | Retrieve item at the fifth index 63 | | sixth | Collection | Retrieve item at the sixth index 64 | | seventh | Collection | Retrieve item at the seventh index 65 | | eighth | Collection | Retrieve item at the eighth index 66 | | ninth | Collection | Retrieve item at the ninth index 67 | | tenth | Collection | Retrieve item at the tenth index 68 | | before | Collection | Get the previous item from the collection 69 | | carbonize | Collection | Convert all collection items into instances of CarbonImmutable 70 | | chunkBy | Collection | Chunks the values from a collection into groups as long the given callback is true 71 | | collectBy | Collection | Get an item at a given key, and collect it 72 | | eachCons | Collection | Get the following consecutive neighbours in a collection from a given chunk size 73 | | extract | Collection | Extract keys from a collection 74 | | filterMap | Collection | Map a collection and remove falsy values in one go 75 | | firstOrFail | Collection | Get the first item or throw an exception 76 | | fromPairs | Collection | Transform a collection into an associative array form collection item 77 | | glob | Collection | Returns a collection of a `glob()` result 78 | | groupByModel | Collection | Similar to `groupBy`, but groups the collection by an Eloquent model 79 | | head | Collection | Retrieves first item from the collection 80 | | ifAny | Collection | Executes the passed callable if the collection isn't empty 81 | | ifEmpty | Collection | Executes the passed callable if the collection is empty 82 | | none | Collection | Checks whether a collection doesn't contain any occurrences of a given item, key-value pair, or passing truth test 83 | | paginate | Collection | Create a `LengthAwarePaginator` instance for the items in the collection 84 | | parallelMap | Collection | Identical to `map` but each item in the collection will be processed in parallel 85 | | pluckToArray | Collection | Returns array of values of a given key 86 | | prioritize | Collection | Move elements to the start of the collection 87 | | rotate | Collection | Rotate the items in the collection with given offset 88 | | sectionBy | Collection | Splits a collection into sections grouped by a given key 89 | | simplePaginate | Collection | Create a `Paginator` instance for the items in the collection 90 | | sliceBefore | Collection | Slice the values out from a collection before the given callback is true 91 | | tail | Collection | Extract the tail from a collection (everything except the first element) 92 | | toPairs | Collection | Transform a collection into an array with pairs 93 | | transformKeys | Collection | Performs a transform operation, but on the collection's keys instead of its values 94 | | transpose | Collection | Rotate a multidimensional array, turning the rows into columns and the columns into rows 95 | | trim | Collection | Maps over each item in the collection and calls PHP's trim() method on it 96 | | validate | Collection | Returns true if the given callback returns true for every item 97 | | withSize | Collection | Create a new collection with the specified amount of items 98 | 99 | ## Contributing 100 | 101 | Thank you for considering a contribution to Elevate. You are welcome to submit a PR containing a new macro or improvements to existing ones, however please also be sure to include a test or tests where appropriate. 102 | 103 | ## Credits 104 | 105 | The library includes macros and / or code obtained from the following open-source packages: 106 | 107 | * [Laravel Collection Macros](https://github.com/spatie/laravel-collection-macros) by [Spatie](https://spatie.be) 108 | * [Laravel Helpers](https://github.com/sebastiaanluca/laravel-helpers) by [sebastiaanluca](https://github.com/sebastiaanluca) 109 | * [String Library](https://github.com/spatie/string) by [Spatie](https://spatie.be) 110 | * [Underscore Library](https://github.com/Anahkiasen/underscore-php) by [Emma Fabre](https://autopergamene.eu) 111 | * [Nette Utilities](https://github.com/nette/utils) by [Nette Foundation](https://nette.org) 112 | 113 | ## License 114 | 115 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 116 | -------------------------------------------------------------------------------- /.php-cs-fixer.cache: -------------------------------------------------------------------------------- 1 | {"php":"8.1.12","version":"3.13.0","indent":" ","lineEnding":"\n","rules":{"blank_line_after_namespace":true,"braces":true,"class_definition":true,"constant_case":true,"elseif":true,"function_declaration":{"closure_function_spacing":"none"},"indentation_type":true,"line_ending":true,"lowercase_keywords":true,"method_argument_space":{"on_multiline":"ensure_fully_multiline","keep_multiple_spaces_after_comma":true},"no_break_comment":true,"no_closing_tag":true,"no_space_around_double_colon":true,"no_spaces_after_function_name":true,"no_spaces_inside_parenthesis":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":{"elements":["property"]},"single_import_per_statement":true,"single_line_after_imports":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"visibility_required":{"elements":["method","property"]},"encoding":true,"full_opening_tag":true,"array_syntax":{"syntax":"short"},"ordered_imports":{"sort_algorithm":"length"},"no_unused_imports":true,"not_operator_with_successor_space":true,"trailing_comma_in_multiline":{"elements":["arrays"]},"phpdoc_scalar":true,"unary_operator_spaces":true,"binary_operator_spaces":{"operators":{"=":"align","=>":"align"}},"blank_line_before_statement":{"statements":["break","continue","declare","return","throw","try"]},"phpdoc_single_line_var_spacing":true,"phpdoc_var_without_name":true,"class_attributes_separation":{"elements":{"method":"one","property":"one"}},"method_chaining_indentation":true,"object_operator_without_whitespace":true,"no_superfluous_phpdoc_tags":true},"hashes":{"src\/Exceptions\/CollectionItemNotFound.php":"77889d9ca75639adeb7137cf6506f306","src\/Macros\/Stringable\/ToArray.php":"8954679daa4e6ce72dd34b7bee05a4ed","src\/Macros\/Stringable\/Insert.php":"10123269a55f866417bd825d81f6568f","src\/Macros\/Stringable\/Collapse.php":"40902f64ef051fc3dd74cf1a54bf076f","src\/Macros\/Stringable\/Get.php":"33a87111331cf90368f61ea7084120e0","src\/Macros\/Stringable\/AppendIf.php":"6f5642f518eff1a40855a9219153c831","src\/Macros\/Stringable\/Possessive.php":"f2c14122adc71f230746ca8cbe3ce72b","src\/Macros\/Stringable\/Segment.php":"fb52dc620dd3f03a6207eaa231498922","src\/Macros\/Stringable\/PadLeft.php":"f1ad29fc7380996b2e8c32d1dcc1afc6","src\/Macros\/Stringable\/PrependIf.php":"438bfff447c5dab3f5abe09155ea5bbc","src\/Macros\/Stringable\/Count.php":"d64df591529c6a98f1f0f2be6fa4dd7a","src\/Macros\/Stringable\/Toggle.php":"89b14177119379ea4769a4fcfe46a3cf","src\/Macros\/Stringable\/PadRight.php":"ab1a6688d4994eba05f7cd706a0f878e","src\/Macros\/Collection\/Validate.php":"6857de331167c741b1966d1708ec8cb2","src\/Macros\/Collection\/Extract.php":"cd28d2a9a8d6aece67ea5cc82264cd8c","src\/Macros\/Collection\/Seventh.php":"8c855ae42ad5d6e3c3176a7730a36c24","src\/Macros\/Collection\/Fifth.php":"a12c33ef760374cb55f721e83d299c3a","src\/Macros\/Collection\/None.php":"2d4c3b4895af2d2ee4931a0a91c8f128","src\/Macros\/Collection\/Eighth.php":"9d1d5703eeb752970b9a926fdcea7895","src\/Macros\/Collection\/FromPairs.php":"3f17fa31b97c622910f24ea15c0243c2","src\/Macros\/Collection\/FirstOrFail.php":"5a3a4a88635dca23e1ae39b95fa8382e","src\/Macros\/Collection\/SliceBefore.php":"3a0d6ebfdd5b40d64554f0eae5837160","src\/Macros\/Collection\/Carbonize.php":"c7384f964ff95518c0dd14fcf1285aef","src\/Macros\/Collection\/IfAny.php":"3fc4cec6bd0576cb8a8cd4aaf030cd13","src\/Macros\/Collection\/Sixth.php":"2176093dbc83623fb7308fa6a1c3f073","src\/Macros\/Collection\/EachCons.php":"30423c86fefe62e3a8386888a8a3890a","src\/Macros\/Collection\/IfEmpty.php":"19913c201aa96261eb9026847fd98fa0","src\/Macros\/Collection\/Tail.php":"2679af55119fad70428c0ea8ccedeefc","src\/Macros\/Collection\/SectionBy.php":"5d79bf0afe0b381404a1daf9225ba8cc","src\/Macros\/Collection\/GroupByModel.php":"c1cd0a27f649a95623162358519df643","src\/Macros\/Collection\/ToPairs.php":"7570fb97716635c1774f9c4073834c66","src\/Macros\/Collection\/Prioritize.php":"d7809f1cbaa041f6e6ddddd817001aeb","src\/Macros\/Collection\/Tenth.php":"26ce48bd66fa1973e3525ad1786430df","src\/Macros\/Collection\/After.php":"212483923b9b2129e5277e141c463e48","src\/Macros\/Collection\/ParallelMap.php":"ef1658f491eff9723112b7fa85450477","src\/Macros\/Collection\/Head.php":"e06c0c26eaa4e9de46c6f3c9e996670c","src\/Macros\/Collection\/At.php":"e8abaf23b3d1f9a3ebaf8805042ac604","src\/Macros\/Collection\/Before.php":"0895f487a4d6649e85ecebe5d65b945c","src\/Macros\/Collection\/Paginate.php":"29a9a3a924eb80ace73b44f811c9a0be","src\/Macros\/Collection\/SimplePaginate.php":"51a18a5e303c3c59219e8bd6b557adc7","src\/Macros\/Collection\/CollectBy.php":"f82122f4eca4b36cc6fd2f29ecb63f10","src\/Macros\/Collection\/Rotate.php":"e4c2b849270ad92c76d4045f7f220c1b","src\/Macros\/Collection\/Fourth.php":"70e8da446cc29e88704e618e1192a1af","src\/Macros\/Collection\/ChunkBy.php":"fddbac09595dcc3131c0b5a82226fec6","src\/Macros\/Collection\/PluckToArray.php":"2c1dcf15ce1955ff586d36ea91bf882c","src\/Macros\/Collection\/FilterMap.php":"aea7421a1f3007e01abb699682c28494","src\/Macros\/Collection\/Third.php":"ac5f6f69e1b46f14a92ccf704f5aed44","src\/Macros\/Collection\/Glob.php":"58c018998775f1a90e5787e63b042ae9","src\/Macros\/Collection\/Trim.php":"e2d75346fe33116fd82df5219fdd2709","src\/Macros\/Collection\/Second.php":"14c54286d59e40aea8f3750f88551749","src\/Macros\/Collection\/Ninth.php":"a38abd69f4e18f65f6a0fc5721d56ceb","src\/Macros\/Collection\/Transpose.php":"b5f23cdab90539a1319fdf8a83582188","src\/Macros\/Collection\/WithSize.php":"57bb4219263c26733607d30f7daae537","src\/Macros\/Collection\/TransformKeys.php":"872d57d4309454272aa09e08717a7158","src\/Macros\/Blade\/Blank.php":"40c8aeeeeae0044a001dbef5b2bb8586","src\/Macros\/Blade\/Filled.php":"dc8d506a8a90856c9c60d2bd39c6f491","src\/ServiceProvider.php":"a71624bff3eef3fa936b096063c80c43","tests\/Stringable\/ToArrayTest.php":"530343cf4cbb0cd74c086070516e614f","tests\/Stringable\/GetTest.php":"66b3c0610ed5f6936879a2d69d482b60","tests\/Stringable\/PossessiveTest.php":"919edaa21ef114dbadb83ade11a376b4","tests\/Stringable\/AppendIfTest.php":"00d4192e9ec886ae3457c6f422a5ca58","tests\/Stringable\/InsertTest.php":"69db17da9405753dde4a62c29148e87b","tests\/Stringable\/SegmentTest.php":"e16cd35fa81207c64f8776e550dac0ef","tests\/Stringable\/CountTest.php":"09bac447523a8f714f33b747852cec18","tests\/Stringable\/CollapseTest.php":"9fc86d42e164742f524a9473a0d9a9f0","tests\/Stringable\/ToggleTest.php":"f29106127ce5d8e3718c413c6ee396a0","tests\/Stringable\/PadLeftTest.php":"010fb5790b1d2d26d579db53ecacee3a","tests\/Stringable\/PrependIfTest.php":"b9c889ad8c1fddfa3b8d2e60a1bfc977","tests\/Stringable\/PadRightTest.php":"f3af0746b10afa991c7e523ed9f190ce","tests\/Collection\/IfEmptyTest.php":"eb71773f01cd479ff8501ec5f116d1cb","tests\/Collection\/HeadTest.php":"c8db3cac650ae77548e1428caf4513cb","tests\/Collection\/AtTest.php":"b0c888a73d9943cc344ffc0d48206939","tests\/Collection\/CollectByTest.php":"aeea7c35b7d6d125b5013e266e02430c","tests\/Collection\/EachConsTest.php":"022c2e599d617b6be80b590195441abf","tests\/Collection\/AfterTest.php":"f4f5f55e7bfc5ca6675ce6f7414918af","tests\/Collection\/BeforeTest.php":"7e6822874cd9aa75ba7018f8e716dbb4","tests\/Collection\/ValidateTest.php":"3e341fca19db03af469b8aa281cd3d6f","tests\/Collection\/NoneTest.php":"64737e4cfb93c1dfea9c26eddbdb53dc","tests\/Collection\/WithSizeTest.php":"183a17808c5215d5772696dea60bd992","tests\/Collection\/FromPairsTest.php":"800e09624d9a961cf0980a7dff986a68","tests\/Collection\/PluckToArrayTest.php":"9d0e764794918d9ef4dc48da18ead596","tests\/Collection\/TailTest.php":"0a3fead0d6fd8842af5fe33be156116d","tests\/Collection\/SliceBeforeTest.php":"45c49e5ba5c56043e4be03c5a6eb8efb","tests\/Collection\/IfAnyTest.php":"12dd0cc16213883dba01754e41910012","tests\/Collection\/ToPairsTest.php":"7f1d74df6b71de6d322d9a9ab6748564","tests\/Collection\/SimplePaginateTest.php":"b032038fd44bf4d985761323bc28c09e","tests\/Collection\/ExtractTest.php":"cc91e90e6d6554c5d4382124d9903f30","tests\/Collection\/CarbonizeTest.php":"7aa37bf4775001750e11d48b3934ad22","tests\/Collection\/SectionByTest.php":"83074a70a118bafe42e7e8dadf15043d","tests\/Collection\/GroupByModelTest.php":"f0e51204f6e222322956d2f7a097cbbe","tests\/Collection\/TrimTest.php":"7afec322191d37907d665c03620df744","tests\/Collection\/GetHumanCountTest.php":"a2a886b7934e54df1daaf7a3b7423f19","tests\/Collection\/PrioritizeTest.php":"6fd458472c168ec0ae6f8c7204e8012c","tests\/Collection\/TransposeTest.php":"56875c82ee3a8c0d81342b4b63746ec1","tests\/Collection\/PaginateTest.php":"dbf1c3a1621ba05b4e31ce76e93a7a30","tests\/Collection\/FirstOrFailTest.php":"f4b898419138c9d020601bbbf6dcd64b","tests\/Collection\/FilterMapTest.php":"305400d17707feef28c8ab89c07978ae","tests\/Collection\/ChunkByTest.php":"c179b45fd48da7fe2df75f521042fcd0","tests\/Collection\/RotateTest.php":"c890764118aa6ac521e49822c5f57c6b","tests\/Collection\/TransformKeysTest.php":"6ffcc9974eee6c45873153b56e28810a","tests\/RegisterTest.php":"b1fcb6351993fc2a2849da4fb7076abe","tests\/Blade\/BlankTest.php":"d3867dba3e3628380a179234e9deb67f","tests\/Blade\/FilledTest.php":"dff70c6ee5fe4c610522766cbf50caf1"}} --------------------------------------------------------------------------------