├── .gitignore ├── logo.png ├── tests ├── TestCase.php └── Unit │ ├── Methods │ └── GlobalHelpersTest.php │ └── Collections │ └── CollectionMacrosTest.php ├── phpcs.xml.dist ├── .editorconfig ├── CODE_OF_CONDUCT.md ├── ISSUE_TEMPLATE.md ├── phpunit.xml ├── LICENSE.md ├── CONTRIBUTING.md ├── PULL_REQUEST_TEMPLATE.md ├── src ├── Methods │ └── helpers.php └── Collections │ └── CollectionMacrosServiceProvider.php ├── .travis.yml ├── composer.json ├── CHANGELOG.md ├── logo.svg └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | composer.phar 2 | composer.lock 3 | vendor 4 | tests/files/ 5 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastiaanluca/laravel-helpers/HEAD/logo.png -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ./src 6 | ./tests 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | ; This file is for unifying the coding style for different editors and IDEs. 2 | ; More information at http://editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | indent_size = 4 9 | indent_style = space 10 | end_of_line = lf 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | [*.yml] 15 | indent_size = 2 16 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | It's simple, really: 4 | 5 | - Everyone is welcome to contribute 6 | - Use common sense at all times 7 | - Be open to other opinions and constructive criticism 8 | - Be friendly 9 | 10 | Feel like someone's in violation of this? [Contact me directly][link-author-email]. 11 | 12 | [link-author-email]: mailto:hello@sebastiaanluca.com 13 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Make it clear if the issue is a **bug**, an **enhancement** or just a **question**. The easiest way to indicate this is to prefix the title, e.g. `[Question] I have a question`. 4 | 5 | Provide a detailed description of the change or addition you are proposing. Include some screenshots or code examples if possible. 6 | 7 | ### Your environment 8 | 9 | If you're reporting a bug or asking a specific question, include as many relevant details about your environment so we can reproduce it. The more, the better. 10 | 11 | - Package version or last commit 12 | - Operating system and version 13 | - PHP version 14 | - Laravel version 15 | - Related package versions 16 | - … 17 | 18 | ## Context 19 | 20 | Why is this change important to you? How would you use it? How can it benefit other users? 21 | 22 | ## Possible implementation 23 | 24 | Not obligatory, but suggest an idea for implementing addition or change. 25 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | ./tests/Feature 23 | 24 | 25 | ./tests/Unit 26 | 27 | 28 | 29 | 30 | src/ 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) 2018 (until present) Sebastiaan Luca 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 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are very welcome and will be fully credited. 4 | 5 | We accept contributions via pull requests. 6 | 7 | ## Pull request guidelines 8 | 9 | - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - Don't go crazy with the formatting. 10 | 11 | - **Add tests** - Your patch won't be accepted if it doesn't have tests. Don't worry though! Feel free to submit a PR without, we'll help you along the way. 12 | 13 | - **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. 14 | 15 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option. 16 | 17 | - **Create feature branches** - Don't ask us to pull from your master branch unless it only contains the PR code. 18 | 19 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. 20 | 21 | - **Send coherent history** - Make sure each commit in your pull request is somewhat meaningful and contains related changes. Don't go overboard by changing a dozen files and doing everything in a single commit. 22 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## PR Type 2 | 3 | What kind of pull request is this? Put an `x` in all the boxes that apply: 4 | 5 | - [ ] Bug fix (non-breaking change which fixes an issue) 6 | - [ ] New feature (non-breaking change which adds functionality) 7 | - [ ] Extend feature (non-breaking change which extends existing functionality) 8 | - [ ] Change feature (non-breaking change which either changes or refactors existing functionality) 9 | - [ ] Breaking change (fix or feature that would cause existing functionality to change) 10 | 11 | ## What does it change? 12 | 13 | Describe your changes in detail. 14 | 15 | ## Why this PR? 16 | 17 | Why is this change required? What problem does it solve? 18 | 19 | ## How has this been tested? 20 | 21 | Please describe in detail how you tested your changes (or are planning on testing them). 22 | 23 | ## Checklist 24 | 25 | To facilitate merging your change and the approval of this PR, please make sure you've reviewed and applied the following: 26 | 27 | - This PR addresses exactly one issue 28 | - All changes were made in a fork of this project (preferably also in a separate branch) 29 | - It follows the code style of this project 30 | - Tests were added to cover the changes 31 | - All previously existing tests still pass 32 | - If the change to the code requires a change to the documentation, it has been updated accordingly 33 | 34 | If you're unsure about any of these, don't hesitate to ask. We're here to help! 35 | -------------------------------------------------------------------------------- /src/Methods/helpers.php: -------------------------------------------------------------------------------- 1 | guest(); 28 | } 29 | } 30 | 31 | if (! function_exists('is_logged_in')) { 32 | /** 33 | * Determine if the current user is authenticated. 34 | * 35 | * @return bool 36 | */ 37 | function is_logged_in() : bool 38 | { 39 | return auth()->check(); 40 | } 41 | } 42 | 43 | if (! function_exists('user')) { 44 | /** 45 | * Get the currently authenticated user. 46 | * 47 | * @return \Illuminate\Contracts\Auth\Authenticatable|null 48 | */ 49 | function user() : ?Authenticatable 50 | { 51 | return auth()->user(); 52 | } 53 | } 54 | 55 | if (! function_exists('me')) { 56 | /** 57 | * Get the currently authenticated user. 58 | * 59 | * @return \Illuminate\Contracts\Auth\Authenticatable|null 60 | */ 61 | function me() : ?Authenticatable 62 | { 63 | return auth()->user(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 7.3 5 | - 7.4 6 | - nightly 7 | 8 | cache: 9 | directories: 10 | - $HOME/.composer/cache 11 | 12 | env: 13 | matrix: 14 | - LARAVEL_VERSION="^7.0" COMPOSER_FLAGS="--prefer-lowest" 15 | - LARAVEL_VERSION="^7.0" COMPOSER_FLAGS="--prefer-stable" 16 | - LARAVEL_VERSION="^8.0" COMPOSER_FLAGS="--prefer-lowest" 17 | - LARAVEL_VERSION="^8.0" COMPOSER_FLAGS="--prefer-stable" 18 | - LARAVEL_VERSION="dev-master" ORCHESTRA_VERSION="dev-master" COMPOSER_FLAGS="--prefer-lowest" MINIMUM_STABILITY="dev" 19 | - LARAVEL_VERSION="dev-master" ORCHESTRA_VERSION="dev-master" COMPOSER_FLAGS="--prefer-stable" MINIMUM_STABILITY="dev" 20 | 21 | matrix: 22 | allow_failures: 23 | - php: nightly 24 | - env: LARAVEL_VERSION="dev-master" ORCHESTRA_VERSION="dev-master" COMPOSER_FLAGS="--prefer-lowest" MINIMUM_STABILITY="dev" 25 | - env: LARAVEL_VERSION="dev-master" ORCHESTRA_VERSION="dev-master" COMPOSER_FLAGS="--prefer-stable" MINIMUM_STABILITY="dev" 26 | fast_finish: true 27 | 28 | before_install: 29 | - composer validate --strict 30 | - travis_retry composer self-update 31 | - if [[ -n ${MINIMUM_STABILITY} ]]; then composer config minimum-stability ${MINIMUM_STABILITY}; echo "Minimum stability set to ${MINIMUM_STABILITY}"; else echo "Minimum stability left unchanged"; fi 32 | - if [[ -n ${ORCHESTRA_VERSION} ]]; then composer require orchestra/testbench=${ORCHESTRA_VERSION} --dev --no-update; else echo "orchestra/testbench version requirement left unchanged"; fi 33 | - composer require laravel/framework=${LARAVEL_VERSION} --no-update 34 | 35 | install: 36 | - travis_retry composer update ${COMPOSER_FLAGS} --no-interaction --prefer-dist 37 | 38 | script: 39 | - vendor/bin/phpunit 40 | 41 | notifications: 42 | email: 43 | on_failure: change 44 | on_success: never 45 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sebastiaanluca/laravel-helpers", 3 | "type": "library", 4 | "description": "An extensive set of Laravel framework helper functions and collection macros.", 5 | "keywords": [ 6 | "laravel", 7 | "helpers", 8 | "collections", 9 | "macros" 10 | ], 11 | "homepage": "https://github.com/sebastiaanluca/laravel-helpers", 12 | "license": "MIT", 13 | "authors": [ 14 | { 15 | "name": "Sebastiaan Luca", 16 | "email": "hello@sebastiaanluca.com", 17 | "homepage": "https://www.sebastiaanluca.com", 18 | "role": "Author" 19 | } 20 | ], 21 | "require": { 22 | "php": "^7.3", 23 | "laravel/framework": "^7.0|^8.0" 24 | }, 25 | "require-dev": { 26 | "kint-php/kint": "^3.3", 27 | "nesbot/carbon": "^1.0|^2.0", 28 | "orchestra/testbench": "^5.1|^6.0", 29 | "phpunit/phpunit": "^8.5" 30 | }, 31 | "suggest": { 32 | "kint-php/kint": "A powerful and modern PHP debugging tool. Required for the debug collection macros.", 33 | "nesbot/carbon": "A simple PHP API extension for DateTime. Required for the carbonize collection macro." 34 | }, 35 | "autoload": { 36 | "psr-4": { 37 | "SebastiaanLuca\\Helpers\\": "src" 38 | }, 39 | "files": [ 40 | "src/Methods/helpers.php" 41 | ] 42 | }, 43 | "autoload-dev": { 44 | "psr-4": { 45 | "SebastiaanLuca\\Helpers\\Tests\\": "tests" 46 | } 47 | }, 48 | "config": { 49 | "sort-packages": true 50 | }, 51 | "extra": { 52 | "laravel": { 53 | "providers": [ 54 | "SebastiaanLuca\\Helpers\\Collections\\CollectionMacrosServiceProvider" 55 | ] 56 | } 57 | }, 58 | "scripts": { 59 | "composer-validate": "@composer validate --no-check-all --strict --ansi", 60 | "test": "vendor/bin/phpunit", 61 | "test-lowest": [ 62 | "composer update --prefer-lowest --prefer-dist --no-interaction --ansi", 63 | "@test" 64 | ], 65 | "test-stable": [ 66 | "composer update --prefer-stable --prefer-dist --no-interaction --ansi", 67 | "@test" 68 | ], 69 | "check": [ 70 | "@composer-validate", 71 | "@test" 72 | ] 73 | }, 74 | "minimum-stability": "dev", 75 | "prefer-stable": true 76 | } 77 | -------------------------------------------------------------------------------- /tests/Unit/Methods/GlobalHelpersTest.php: -------------------------------------------------------------------------------- 1 | $locale = 'randomlocale']); 19 | 20 | $this->assertSame($locale, locale()); 21 | } 22 | 23 | /** 24 | * @test 25 | */ 26 | public function locale returns the fallback locale if locale not set() : void 27 | { 28 | config(['app.locale' => null]); 29 | config(['app.fallback_locale' => $locale = 'fallbacklocale']); 30 | 31 | $this->assertSame($locale, locale()); 32 | } 33 | 34 | /** 35 | * @test 36 | */ 37 | public function is_guest returns true if the current user is a guest() : void 38 | { 39 | $this->assertTrue(is_guest()); 40 | } 41 | 42 | /** 43 | * @test 44 | */ 45 | public function is_guest returns false if the current user is not a guest() : void 46 | { 47 | $this->be(new User); 48 | 49 | $this->assertFalse(is_guest()); 50 | } 51 | 52 | /** 53 | * @test 54 | */ 55 | public function is_logged_in returns false if the current user is not logged in() : void 56 | { 57 | $this->assertFalse(is_logged_in()); 58 | } 59 | 60 | /** 61 | * @test 62 | */ 63 | public function is_logged_in returns true if the current user is logged in() : void 64 | { 65 | $this->be(new User); 66 | 67 | $this->assertTrue(is_logged_in()); 68 | } 69 | 70 | /** 71 | * @test 72 | */ 73 | public function user returns null if the current user is not logged in() : void 74 | { 75 | $this->assertNull(user()); 76 | } 77 | 78 | /** 79 | * @test 80 | */ 81 | public function user returns the user object if the current user is logged in() : void 82 | { 83 | $this->be(new User); 84 | 85 | $this->assertInstanceOf( 86 | Authenticatable::class, 87 | user() 88 | ); 89 | } 90 | 91 | /** 92 | * @test 93 | */ 94 | public function me returns null if the current user is not logged in() : void 95 | { 96 | $this->assertNull(me()); 97 | } 98 | 99 | /** 100 | * @test 101 | */ 102 | public function me returns the user object if the current user is logged in() : void 103 | { 104 | $this->be(new User); 105 | 106 | $this->assertInstanceOf( 107 | Authenticatable::class, 108 | me() 109 | ); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/Collections/CollectionMacrosServiceProvider.php: -------------------------------------------------------------------------------- 1 | items)->map(function ($time) { 26 | return new Carbon($time); 27 | }); 28 | }); 29 | 30 | /* 31 | * Reduce each collection item to the value found between a given start and end string. 32 | */ 33 | 34 | Collection::macro('between', function ($start, $end = null) { 35 | $end = $end ?? $start; 36 | 37 | return collect($this->items)->reduce(function ($items, $value) use ($start, $end) { 38 | if (preg_match('/^' . $start . '(.*)' . $end . '$/', $value, $matches)) { 39 | $items[] = $matches[1]; 40 | } 41 | 42 | return collect($items); 43 | }); 44 | }); 45 | 46 | /* 47 | * Perform an operation on the collection's keys. 48 | */ 49 | 50 | Collection::macro('transformKeys', function (callable $operation) { 51 | return collect($this->items)->mapWithKeys(function ($item, $key) use ($operation) { 52 | return [$operation($key) => $item]; 53 | }); 54 | }); 55 | 56 | /* 57 | * Transpose (flip) a collection matrix (array of arrays). 58 | * 59 | * @see https://adamwathan.me/2016/04/06/cleaning-up-form-input-with-transpose/ 60 | */ 61 | 62 | Collection::macro('transpose', function () { 63 | if ($this->isEmpty()) { 64 | return $this; 65 | } 66 | 67 | $items = array_map(function (...$items) { 68 | return $items; 69 | }, ...$this->values()); 70 | 71 | return new static($items); 72 | }); 73 | 74 | /* 75 | * Transpose (flip) a collection matrix (array of arrays) while keeping its columns and row headers intact. 76 | * 77 | * Please note that a row missing a column another row does have can only occur for one column. It cannot 78 | * parse more than one missing column. 79 | */ 80 | 81 | Collection::macro('transposeWithKeys', function (?array $rows = null) { 82 | if ($this->isEmpty()) { 83 | return $this; 84 | } 85 | 86 | if ($rows === null) { 87 | $rows = $this->values()->reduce(function (array $rows, array $values) { 88 | return array_unique(array_merge($rows, array_keys($values))); 89 | }, []); 90 | } 91 | 92 | $keys = $this->keys()->toArray(); 93 | 94 | // Transpose the matrix 95 | $items = array_map(function (...$items) use ($keys) { 96 | // The collection's keys now become column headers 97 | return array_combine($keys, $items); 98 | }, ...$this->values()); 99 | 100 | // Add the new row headers 101 | $items = array_combine($rows, $items); 102 | 103 | return new static($items); 104 | }); 105 | 106 | Collection::macro('d', function () { 107 | d($this); 108 | 109 | return $this; 110 | }); 111 | 112 | Collection::macro('ddd', function () { 113 | ddd($this); 114 | }); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `sebastiaanluca/laravel-helpers` will be documented in this file. 4 | 5 | Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) principles. 6 | 7 | ## 6.0.0 (2020-10-19) 8 | 9 | ### Added 10 | 11 | - Added support for Laravel 8 12 | 13 | ### Removed 14 | 15 | - Dropped support for Laravel 6 16 | 17 | ## 5.0.0 (2020-04-24) 18 | 19 | ### Added 20 | 21 | - Added support for Laravel 7 22 | 23 | ### Removed 24 | 25 | - Dropped support for Laravel 5 26 | - Dropped support for PHP 7.2 27 | 28 | ## 4.0.0 (2019-08-14) 29 | 30 | ### Added 31 | 32 | - Added support for Laravel 6.0 33 | 34 | ## 3.0.0 (2019-02-27) 35 | 36 | ### Added 37 | 38 | - Added support for Laravel 5.8 39 | 40 | ### Removed 41 | 42 | - Dropped support for Laravel 5.7 and lower 43 | 44 | ### Fixed 45 | 46 | - Correctly tag Laravel version constraints 47 | 48 | ## 2.1.0 (2018-09-04) 49 | 50 | ### Added 51 | 52 | - Run tests against Laravel 5.7 53 | 54 | ## 2.0.0 (2018-07-22) 55 | 56 | ### Added 57 | 58 | - Added logo (by caneco) 59 | - Added `is_guest` helper 60 | - Added `is_logged_in` helper 61 | - Added `user` helper 62 | - Added `me` helper 63 | 64 | ### Changed 65 | 66 | - Added better installation instructions in readme 67 | - Simplified all tests 68 | - Autoload global helpers instead of using a service provider 69 | 70 | ### Removed 71 | 72 | - ⚠️ Extracted all non-Laravel helpers to [individual packages](https://github.com/sebastiaanluca/php-helpers) 73 | - ⚠️ Removed support for PHP 7.1 and below 74 | - ⚠️ Removed support for Laravel 5.5 and below 75 | - Removed deprecated `use Laravelista\Ekko\Ekko;` import 76 | - Removed laravelcollective/html and laravelista/ekko composer dev dependencies 77 | 78 | ### Fixed 79 | 80 | - Upgraded Mockery dependency to fix a test error on PHP 7.2 (see https://github.com/mockery/mockery/pull/718) 81 | 82 | ## 1.0.3 (2018-07-21) 83 | 84 | ### Fixed 85 | 86 | - Fixed transposing of an empty collection 87 | 88 | ## 1.0.2 (2017-11-05) 89 | 90 | ### Fixed 91 | 92 | - Use the item pipe operator class identifier instead of a hardcoded `$$` string ([#11](https://github.com/sebastiaanluca/laravel-helpers/pull/11)) 93 | 94 | ## 1.0.1 (2017-07-11) 95 | 96 | ### Fixed 97 | 98 | - Fixed method helper readme example 99 | 100 | ## 1.0.0 (2017-07-10) 101 | 102 | ### Added 103 | 104 | - Set up testing environment and add tests for each feature 105 | - Added support for Laravel 5.5 106 | - Added `sss_if` global helper 107 | - Added a shorthand `constants()` method to the `Constants` trait 108 | 109 | ### Changed 110 | 111 | - Locked down dependencies more strictly, but allow optional use of each helper 112 | - Added type hints where possible 113 | - Tweaked Travis test script 114 | - Renamed global method helpers service provider 115 | - Renamed collection service provider 116 | - `transposeWithKeys` now automatically guesses the row header names and allows you to override them 117 | - Renamed constant helper trait to `Constants` 118 | - Renamed `hasMethod` to `hasMethodOfType` in `MethodHelper` 119 | - Renamed `ReflectionTrait` to `ProvidesClassInfo` 120 | - Renamed `public_method_exists` global helper to `has_public_method` 121 | 122 | ### Fixed 123 | 124 | - Fixed `MethodHelper::hasMethodOfType` throwing exception if third `$type` parameter was not private, protected, or public 125 | 126 | ### Removed 127 | 128 | - Dropped support for Laravel 5.1, 5.2, and 5.3 129 | - Extracted module service provider (moved to [laravel-resource-flow](https://github.com/sebastiaanluca/laravel-resource-flow)) 130 | - Extracted base Eloquent model (moved to [laravel-resource-flow](https://github.com/sebastiaanluca/laravel-resource-flow)) 131 | - Extracted queueable job (moved to [laravel-resource-flow](https://github.com/sebastiaanluca/laravel-resource-flow)) 132 | - Removed `mapWithIntegerKeys` collection macro (fixed in Laravel 5.4.x) 133 | - Removed HTML and form helpers (tip: use Spatie's macroable https://github.com/spatie/laravel-html package instead) 134 | - Removed `is_active_route` global helper (use Ekko's default global helpers instead) 135 | 136 | ## 0.5.2 (2017-02-14) 137 | 138 | ### Changed 139 | 140 | - Make get constants on ConstantTrait public 141 | 142 | ## 0.5.1 (2017-02-10) 143 | 144 | ### Changed 145 | 146 | - Add ID to guards in BaseEloquentModel 147 | 148 | ## 0.5.0 (2017-02-10) 149 | 150 | ### Added 151 | 152 | - Added BaseEloquentModel 153 | 154 | ## 0.4.0 (2017-02-10) 155 | 156 | ### Added 157 | 158 | - Added QueueableJob 159 | 160 | ## 0.3.1 161 | 162 | ### Added 163 | 164 | - Added a check for Laravel 5.4's `Illuminate\Session\EncryptedStore::getToken()` that was changed to `token()`. 165 | -------------------------------------------------------------------------------- /logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/Unit/Collections/CollectionMacrosTest.php: -------------------------------------------------------------------------------- 1 | assertEquals( 19 | collect([ 20 | new Carbon('yesterday'), 21 | new Carbon('tomorrow'), 22 | new Carbon('2017-07-01'), 23 | ]), 24 | collect([ 25 | 'yesterday', 26 | 'tomorrow', 27 | '2017-07-01', 28 | ])->carbonize() 29 | ); 30 | } 31 | 32 | /** 33 | * @test 34 | */ 35 | public function it creates a collection of values found between two given values() : void 36 | { 37 | $this->assertEquals( 38 | collect([ 39 | 'value1', 40 | 'value2', 41 | 'value3', 42 | ]), 43 | collect([ 44 | '"value1"', 45 | '"value2"', 46 | '"value3"', 47 | ])->between('"', '"') 48 | ); 49 | } 50 | 51 | /** 52 | * @test 53 | */ 54 | public function it creates a collection of values found between one given value() : void 55 | { 56 | $this->assertEquals( 57 | collect([ 58 | 'value1', 59 | 'value2', 60 | 'value3', 61 | ]), 62 | collect([ 63 | '"value1"', 64 | '"value2"', 65 | '"value3"', 66 | ])->between('"') 67 | ); 68 | } 69 | 70 | /** 71 | * @test 72 | */ 73 | public function it transforms keys using a callable() : void 74 | { 75 | $this->assertEquals( 76 | collect([ 77 | 'A' => 'value', 78 | 'B' => 'value', 79 | 'C' => 'value', 80 | ]), 81 | collect([ 82 | 'a' => 'value', 83 | 'b' => 'value', 84 | 'c' => 'value', 85 | ])->transformKeys('strtoupper') 86 | ); 87 | } 88 | 89 | /** 90 | * @test 91 | */ 92 | public function it transforms keys using a callback() : void 93 | { 94 | $this->assertEquals( 95 | collect([ 96 | 'prefix-a' => 'value', 97 | 'prefix-b' => 'value', 98 | 'prefix-c' => 'value', 99 | ]), 100 | collect([ 101 | 'a' => 'value', 102 | 'b' => 'value', 103 | 'c' => 'value', 104 | ])->transformKeys(function (string $key) { 105 | return 'prefix-' . $key; 106 | }) 107 | ); 108 | } 109 | 110 | /** 111 | * @test 112 | */ 113 | public function it transposes a matrix collection() : void 114 | { 115 | $this->assertEquals( 116 | collect([ 117 | [1, 4, 7], 118 | [2, 5, 8], 119 | [3, 6, 9], 120 | ]), 121 | collect([ 122 | [1, 2, 3], 123 | [4, 5, 6], 124 | [7, 8, 9], 125 | ])->transpose() 126 | ); 127 | } 128 | 129 | /** 130 | * @test 131 | */ 132 | public function it transposes a matrix collection including keys() : void 133 | { 134 | $this->assertEquals( 135 | collect([ 136 | 'id' => [ 137 | 'A' => 1, 138 | 'B' => 2, 139 | 'C' => 3, 140 | ], 141 | 'someName' => [ 142 | 'A' => 'name1', 143 | 'B' => 'name2', 144 | 'C' => 'name3', 145 | ], 146 | ]), 147 | collect([ 148 | 'A' => [ 149 | 'id' => 1, 150 | 'name' => 'name1', 151 | ], 152 | 'B' => [ 153 | 'id' => 2, 154 | 'name' => 'name2', 155 | ], 156 | 'C' => [ 157 | 'id' => 3, 158 | 'name' => 'name3', 159 | ], 160 | ])->transposeWithKeys(['id', 'someName']) 161 | ); 162 | } 163 | 164 | /** 165 | * @test 166 | */ 167 | public function it transposes a matrix collection including keys automatically() : void 168 | { 169 | $this->assertEquals( 170 | collect([ 171 | 'id' => [ 172 | 'A' => 1, 173 | 'B' => 2, 174 | 'C' => 3, 175 | ], 176 | 'name' => [ 177 | 'A' => 'name1', 178 | 'B' => 'name2', 179 | 'C' => 'name3', 180 | ], 181 | ]), 182 | collect([ 183 | 'A' => [ 184 | 'id' => 1, 185 | 'name' => 'name1', 186 | ], 187 | 'B' => [ 188 | 'id' => 2, 189 | 'name' => 'name2', 190 | ], 191 | 'C' => [ 192 | 'id' => 3, 193 | 'name' => 'name3', 194 | ], 195 | ])->transposeWithKeys() 196 | ); 197 | } 198 | 199 | /** 200 | * @test 201 | */ 202 | public function it transposes a matrix collection including keys automatically and handles extra fields() : void 203 | { 204 | $this->assertEquals( 205 | collect([ 206 | 'id' => [ 207 | 'A' => 1, 208 | 'B' => 2, 209 | 'C' => 3, 210 | ], 211 | 'name' => [ 212 | 'A' => 'name1', 213 | 'B' => 'name2', 214 | 'C' => 'name3', 215 | ], 216 | 'extra' => [ 217 | 'A' => null, 218 | 'B' => 'extra2', 219 | 'C' => null, 220 | ], 221 | ]), 222 | collect([ 223 | 'A' => [ 224 | 'id' => 1, 225 | 'name' => 'name1', 226 | ], 227 | 'B' => [ 228 | 'id' => 2, 229 | 'name' => 'name2', 230 | 'extra' => 'extra2', 231 | ], 232 | 'C' => [ 233 | 'id' => 3, 234 | 'name' => 'name3', 235 | ], 236 | ])->transposeWithKeys() 237 | ); 238 | } 239 | 240 | public function test it can transpose an empty collection() : void 241 | { 242 | $this->assertEquals(collect(), collect()->transpose()); 243 | $this->assertEquals(collect(), collect()->transposeWithKeys()); 244 | } 245 | 246 | /** 247 | * Get package providers. 248 | * 249 | * @param \Illuminate\Foundation\Application $app 250 | * 251 | * @return array 252 | */ 253 | protected function getPackageProviders($app) : array 254 | { 255 | return [ 256 | CollectionMacrosServiceProvider::class, 257 | ]; 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |

6 | Latest stable release 7 | Software license 8 | Build status 9 | Total downloads 10 | Total downloads 11 |

12 | 13 |

14 | Read my blog 15 | View my other packages and projects 16 | Follow @sebastiaanluca on Twitter 17 | Share this package on Twitter 18 |

19 | 20 |

21 | An extensive set of Laravel framework helper functions and collection macros. 22 |

23 | 24 | ## Table of contents 25 | 26 | - [Requirements](#requirements) 27 | - [How to install](#how-to-install) 28 | - [Upgrading from 1.x](#upgrading-from-1x) 29 | - [Framework helper functions](#framework-helper-functions) 30 | - [locale](#locale) 31 | - [is_guest](#is_guest) 32 | - [is\_logged\_in](#is_logged_in) 33 | - [me](#me) 34 | - [user](#user) 35 | - [Collection macros](#collection-macros) 36 | - [Carbonize](#carbonize) 37 | - [Between](#between) 38 | - [transformKeys](#transformkeys) 39 | - [transpose](#transpose) 40 | - [transposeWithKeys](#transposewithkeys) 41 | - [d](#d) 42 | - [ddd](#ddd) 43 | - [License](#license) 44 | - [Change log](#change-log) 45 | - [Testing](#testing) 46 | - [Contributing](#contributing) 47 | - [Security](#security) 48 | - [Credits](#credits) 49 | - [About](#about) 50 | 51 | ## Requirements 52 | 53 | - PHP 7.3 or higher 54 | - Laravel 7.0 or higher 55 | 56 | ## How to install 57 | 58 | Just add the package to your project using Composer and Laravel will auto-discover it: 59 | 60 | ```bash 61 | composer require sebastiaanluca/laravel-helpers 62 | ``` 63 | 64 | If you want to use the collection debug macros, install the [kint-php/kint](https://github.com/raveren/kint) package as a dev dependency: 65 | 66 | ```bash 67 | composer require kint-php/kint --dev 68 | ``` 69 | 70 | ## Upgrading from 1.x 71 | 72 | All essential generic PHP helpers have been extracted to their own [sebastiaanluca/php-helpers](https://github.com/sebastiaanluca/php-helpers) package and some other helpers have been removed in anticipation of their own package. In effect and from now on, Laravel Helpers will only contain helpers for the Laravel framework. 73 | 74 | [See the changelog](CHANGELOG.md#200-2018-07-22) for more information. 75 | 76 | ## Framework helper functions 77 | 78 | ### locale 79 | 80 | Get the active app locale or the fallback locale if it's missing or not set. 81 | 82 | ```php 83 | locale(); 84 | 85 | // "en" 86 | ``` 87 | 88 | ### is_guest 89 | 90 | Determine if the current user is a guest. 91 | 92 | The opposite of [is_logged_in](#is_logged_in). 93 | 94 | ```php 95 | // When not authenticated 96 | is_guest(); 97 | 98 | // true 99 | 100 | // When authenticated as a user 101 | is_guest(); 102 | 103 | // false 104 | ``` 105 | 106 | ### is\_logged\_in 107 | 108 | Determine if the current user is authenticated. 109 | 110 | The opposite of [is_guest](#is_guest). 111 | 112 | ```php 113 | // When not authenticated 114 | is_logged_in(); 115 | 116 | // false 117 | 118 | // When authenticated as a user 119 | is_logged_in(); 120 | 121 | // true 122 | ``` 123 | 124 | ### user 125 | 126 | Get the currently authenticated user (if there is one). 127 | 128 | When logged in, returns your user model or object that implements `\Illuminate\Contracts\Auth\Authenticatable`. 129 | 130 | ```php 131 | // When not authenticated 132 | user(); 133 | 134 | // null 135 | 136 | // When authenticated as a user 137 | user(); 138 | 139 | // Illuminate\Foundation\Auth\User {} 140 | ``` 141 | 142 | ### me 143 | 144 | Get the currently authenticated user (if there is one). 145 | 146 | When logged in, returns your user model or object that implements `\Illuminate\Contracts\Auth\Authenticatable`. 147 | 148 | An alternative for [user](#user). 149 | 150 | ```php 151 | // When not authenticated 152 | me(); 153 | 154 | // null 155 | 156 | // When authenticated as a user 157 | me(); 158 | 159 | // Illuminate\Foundation\Auth\User {} 160 | ``` 161 | 162 | ## Collection macros 163 | 164 | ### carbonize 165 | 166 | Create Carbon instances from items in a collection. 167 | 168 | ```php 169 | collect([ 170 | 'yesterday', 171 | 'tomorrow', 172 | '2017-07-01', 173 | ])->carbonize(); 174 | 175 | /* 176 | Illuminate\Support\Collection { 177 | all: [ 178 | Carbon\Carbon { 179 | "date": "2017-07-09 00:00:00.000000", 180 | "timezone_type": 3, 181 | "timezone": "UTC", 182 | }, 183 | Carbon\Carbon { 184 | "date": "2017-07-11 00:00:00.000000", 185 | "timezone_type": 3, 186 | "timezone": "UTC", 187 | }, 188 | Carbon\Carbon { 189 | "date": "2017-07-01 00:00:00.000000", 190 | "timezone_type": 3, 191 | "timezone": "UTC", 192 | }, 193 | ], 194 | } 195 | */ 196 | ``` 197 | 198 | ### between 199 | 200 | Reduce each collection item to the value found between a given start and end string. 201 | 202 | The second parameter is optional and falls back to the start string if `null`. 203 | 204 | ```php 205 | collect([ 206 | '"value1"', 207 | '"value2"', 208 | '"value3"', 209 | ])->between('"', '"'); 210 | 211 | /* 212 | Illuminate\Support\Collection { 213 | all: [ 214 | "value1", 215 | "value2", 216 | "value3", 217 | ], 218 | } 219 | */ 220 | ``` 221 | 222 | ### transformKeys 223 | 224 | Perform an operation on the collection's keys. 225 | 226 | The callable operation can either be a globally available method or a closure. 227 | 228 | ```php 229 | collect([ 230 | 'a' => 'value', 231 | 'b' => 'value', 232 | 'c' => 'value', 233 | ])->transformKeys('strtoupper'); 234 | 235 | /* 236 | Illuminate\Support\Collection { 237 | all: [ 238 | "A" => "value", 239 | "B" => "value", 240 | "C" => "value", 241 | ], 242 | } 243 | */ 244 | ``` 245 | 246 | ```php 247 | collect([ 248 | 'a' => 'value', 249 | 'b' => 'value', 250 | 'c' => 'value', 251 | ])->transformKeys(function (string $key) { 252 | return 'prefix-' . $key; 253 | }); 254 | 255 | /* 256 | Illuminate\Support\Collection { 257 | all: [ 258 | "prefix-a" => "value", 259 | "prefix-b" => "value", 260 | "prefix-c" => "value", 261 | ], 262 | } 263 | */ 264 | ``` 265 | 266 | ### transpose 267 | 268 | Transpose (flip) a collection matrix (array of arrays) so its columns become rows and its rows become columns. 269 | 270 | ```php 271 | collect([ 272 | [1, 2, 3], 273 | [4, 5, 6], 274 | [7, 8, 9], 275 | ])->transpose(); 276 | 277 | /* 278 | Illuminate\Support\Collection { 279 | all: [ 280 | [1, 4, 7], 281 | [2, 5, 8], 282 | [3, 6, 9], 283 | ], 284 | } 285 | */ 286 | ``` 287 | 288 | ### transposeWithKeys 289 | 290 | Flip a collection of rows and values per column so its columns become rows and its rows become columns. 291 | 292 | Before: 293 | 294 | | | id | name | 295 | |---|----|-------| 296 | | A | 1 | James | 297 | | B | 2 | Joe | 298 | | C | 3 | Jonas | 299 | 300 | After: 301 | 302 | | | A | B | C | 303 | |------|-------|-----|-------| 304 | | id | 1 | 2 | 3 | 305 | | name | James | Joe | Jonas | 306 | 307 | How to use: 308 | 309 | ```php 310 | collect([ 311 | 'A' => [ 312 | 'id' => 1, 313 | 'name' => 'James', 314 | ], 315 | 'B' => [ 316 | 'id' => 2, 317 | 'name' => 'Joe', 318 | ], 319 | 'C' => [ 320 | 'id' => 3, 321 | 'name' => 'Jonas', 322 | ], 323 | ])->transposeWithKeys(); 324 | 325 | /* 326 | Illuminate\Support\Collection { 327 | all: [ 328 | "id" => [ 329 | "A" => 1, 330 | "B" => 2, 331 | "C" => 3, 332 | ], 333 | "name" => [ 334 | "A" => "James", 335 | "B" => "Joe", 336 | "C" => "Jonas", 337 | ], 338 | ], 339 | } 340 | */ 341 | ``` 342 | 343 | You can also pass some row header names if you don't want them to be automatically guessed. You'd then call the macro with `transposeWithKeys(['myID', 'row2'])` and the resulting rows would be `myID` and `row2` instead of `id` and `name` respectively. 344 | 345 | ### d 346 | 347 | Display structured debug information on the collection using Kint. Can be called multiple times during a collection's method chain and outputs debug information at each point of use. Continues script execution afterwards. 348 | 349 | Explicitly requires the [kint-php/kint](https://github.com/raveren/kint) package. 350 | 351 | ```php 352 | collect([ 353 | 'id' => 6, 354 | 'name' => 'Sebastiaan', 355 | ]) 356 | ->d() 357 | ->put('role', 'author') 358 | ->d(); 359 | ``` 360 | 361 | ### ddd 362 | 363 | Display structured debug information on the collection using Kint. Halts script execution afterwards, so it can only be called once during a collection's method chain. 364 | 365 | Explicitly requires the [kint-php/kint](https://github.com/raveren/kint) package. 366 | 367 | ```php 368 | collect([ 369 | 'id' => 6, 370 | 'name' => 'Sebastiaan', 371 | ]) 372 | ->d() 373 | ->put('role', 'author') 374 | ->ddd(); 375 | ``` 376 | 377 | ## License 378 | 379 | This package operates under the MIT License (MIT). Please see [LICENSE](LICENSE.md) for more information. 380 | 381 | ## Change log 382 | 383 | Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently. 384 | 385 | ## Testing 386 | 387 | ```bash 388 | composer install 389 | composer test 390 | ``` 391 | 392 | ## Contributing 393 | 394 | Please see [CONTRIBUTING](CONTRIBUTING.md) and [CODE OF CONDUCT](CODE_OF_CONDUCT.md) for details. 395 | 396 | ## Security 397 | 398 | If you discover any security related issues, please email [hello@sebastiaanluca.com][link-author-email] instead of using the issue tracker. 399 | 400 | ## Credits 401 | 402 | - [Sebastiaan Luca][link-github-profile] 403 | - Logo by [Vitor Caneco](https://github.com/caneco) 404 | - [All Contributors][link-contributors] 405 | 406 | ## About 407 | 408 | My name is Sebastiaan and I'm a freelance Laravel developer specializing in building custom Laravel applications. Check out my [portfolio][link-portfolio] for more information, [my blog][link-blog] for the latest tips and tricks, and my other [packages][link-packages] to kick-start your next project. 409 | 410 | Have a project that could use some guidance? Send me an e-mail at [hello@sebastiaanluca.com][link-author-email]! 411 | 412 | [link-packagist]: https://packagist.org/packages/sebastiaanluca/laravel-helpers 413 | [link-travis]: https://travis-ci.org/sebastiaanluca/laravel-helpers 414 | [link-contributors]: ../../contributors 415 | 416 | [link-portfolio]: https://www.sebastiaanluca.com 417 | [link-blog]: https://blog.sebastiaanluca.com 418 | [link-packages]: https://packagist.org/packages/sebastiaanluca 419 | [link-github-profile]: https://github.com/sebastiaanluca 420 | [link-author-email]: mailto:hello@sebastiaanluca.com 421 | --------------------------------------------------------------------------------