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 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
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 |
--------------------------------------------------------------------------------