Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.4] Add tap method to collection #17756

Merged
merged 2 commits into from
Feb 6, 2017
Merged

[5.4] Add tap method to collection #17756

merged 2 commits into from
Feb 6, 2017

Conversation

arjasco
Copy link
Contributor

@arjasco arjasco commented Feb 3, 2017

I noticed the tap function in helpers and thought it would be pretty useful in collections. The purpose is to "tap into" method chains without modifying the result of the previous call, we seem to do a lot of chaining with collections.

Creating a new collection to pass to the callback because there are some methods which if called on the collection will change the items. eg. the pop method.

@taylorotwell
Copy link
Member

Interesting. Can you share the real use case you came across for this?

@GrahamCampbell GrahamCampbell changed the title Add tap method to collection [5.4] Add tap method to collection Feb 3, 2017
@@ -827,6 +827,19 @@ public function pipe(callable $callback)
}

/**
* Pass the collection to the given callback and return the current instance.
*
* @param callable $callback
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cs

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nobody knows what "cs" means.

@arjasco
Copy link
Contributor Author

arjasco commented Feb 5, 2017

My use case for this was to help with debugging a huge series of collections without breaking them apart, reassigning them another var. This also means i can perform some extra logic without affecting the next result

Quick example maybe:

collect()
    ->sort(...)
    ->tap(function ($collection) {
        Log::info($collection->toArray()));
    })
    ->groupBy(...)
    ->tap(function ($collection) {
        dd($collection);
    })

You could potentially tap into a collection chain and fire events with the data at the current point.

collect($memebers)
    ->where('active', 1)
    ->tap(function ($collection) {
       $this->dispatch(new ActiveMembersEvent($collection));
    })
    ->where('plan', 1)
    ->tap(function ($collection) {
       $this->dispatch(new Plan1SpecifcMembersEvent($collection));
    })

Testing, making some assertions at various stages could also be a use.

@JosephSilber Good point, I did look at this but wasn't sure exactly if this was correct. There is actually a bit of a divide across what tap should actually do. Some say it should tap into a method chain so you can perform some action with the data at that specific point in the chain without affecting the result of the previous method as it gets passed onto the next. Yet some say it should be able to modify the result before it's passed onto the next.. which sounds more like a pipeline to me.

The use of the tap helper confuses me when used in some areas of the framework anyway.
https://github.com/laravel/framework/blob/5.4/src/Illuminate/Foundation/AliasLoader.php#L89

loadFacade doesn't actually return anything (says bool), if it did it would actually be a string (the path to the facade) so why do we need tap? I've seen some others that the callback doesn't even use the value thats passed to it...

I believe some of it's other use is just to tidy up on not having var assignments and then returning..

@taylorotwell taylorotwell merged commit 5cd2eda into laravel:5.4 Feb 6, 2017
@sebdesign
Copy link
Contributor

I'm here just to say that ->tap('dump')-> has been so useful lately!

appleboy pushed a commit to laravel-taiwan/docs that referenced this pull request Jul 8, 2017
* Correct the note regarding assertJson

* Add view() usage information to notifications

* Add note about assertJsonStructure()

* adjust wordin

* remove second param

* Fix typo in Filesystem doc

* update wording

* Document Passport::actingAs()

*          document the changes in model create and forceCreate

* update wording

*        add notes about bind and instance

* update wording

* add note on optional fields

* remove word

* add note on normaliation

* add note about autoloading

*    document assertJsonFragment

*    minor edit

* Update Mix documentation about `version`

* spelling

* Example for redirectTo() Method

Add simple return example, to clarify redirectTo() method, if used, should return a path string.

* document intersect method

* Added changes to Event Fake changes

added changes for `assertNotFired` to `assertNotDispatched`

* Document Route::resourceVerbs() method

* Update upgrade.md

* fix wording

* wording

*    use BrowserKitTestCase

* fix: remove comma

* Better wording for Cashier warning

* update docs

* Remove compiled.php to upgrade guide

laravel/framework#17003 (comment)

* Update upgrade.md

* Fix method name in dusk.md

Method is called `elements`

* Change PHPUnit to 5.7

composer.json has been updated a week ago;
laravel/laravel@926f53b

* give more clarity

* Correct reference to resources directory name

When describing the resource_path() helper, there was an incorrect mention of the storage directory. Likely due to copy & paste.

* Update http-tests.md

Tests are now using namespaces. We need to access global scope for User::class

* import class

* 📝 add documentation for collection when method

Documentation for the collection `when` method introduced in
laravel/framework#17917.

* update wording

* added to docs

* use correct name of method

* Adding brackets.

* Changing heading

* Removing references to the .homestead directory.

This commit (laravel/homestead@06b52c7) removes the `.homestead` directory, placing the `Homestead.yaml` file in the Homestead directory instead.

* Add missing config entry.

* Update notifications.md

* work on docs

* add notes for random dropdown selection

related to this Dusk PR

laravel/dusk#140

* Update dusk.md

* Updated dusk.md

Add docs for radio selection assertions
re: laravel/dusk#138

* Added note about indentation level on markdown emails

* adjust wording

* Removes PM2 from homestead docs

Not included in vagrant box

* Extend Mix docs

* fix formatting and wording

* fix mistake in stylus

* Fix typo in Homestead doc

* ✨ 📚 Add JSON Config info, share() docs, notes about using stable versions

* Replace htmlentities with htmlspecialchars

* fix various errors and problems

* Use path to sass instead of less

* use uri() instead of getPath() for Route

* Replace "login" with "log in"

* Add note about the removal of the ConfigureLogging

As per this commit the ConfigureLogging bootstrapper is no more in 5.4 with the Monolog setup being moved to a base service provider in Illuminate\Foundation\Application laravel/framework@919f21b#diff-67364880bdf444edbf5e384f3686b9b9

* update dusk.md

Added queryString assertions to list of available assertions.

* Update homestead.md

* added docs for testing file uploads

* More clarification of the example commands used.

* Document Collection::whereNotIn()

* Update mix.md

>Behind the scenes, Mix will download and include the appropriate `babel-preset-react` Babel plug-in.

It used to say:

>Behind the scenes, React will download and include the appropriate `babel-preset-react` Babel plug-in.

* Update collections.md

* fix wording

* Change dot to semicolon

* Update mix.md

Add missing word.

* Update structure

Add `channels,php` to `routes` directory.

* Update structure.md

* Add new drag methods to documentation

* fix formatting

* Terminable route middleware clarification

There was some confusion with some developers because the documentation seemed to say that terminable middleware has to be defined in your *global* middleware list, but in fact terminable middleware can be used as *route* middleware as well.

* Update middleware.md

* e function sets double_encode to false

This behaviour is not intuitive as the parameter is set to true per default in htmlspecialchars.

* Fixed typo error.

* Added kebab_case() to the string helpers

Was this method not documented so it will not break the 6 methods per column on 3 columns?

* Added kebab_case() to the string helpers

Was this method not documented so it will not break the 6 methods per column on 3 columns?

* Update helpers.md

* Mention the array_wrap helper

* tweak wording

* changes for custom pivot table model

The pivot model must extend the the relations/pivot class

* Adding semicolon.

* Fixed typo

* Update authorization.md

Include namespace in 'Actions that don't require models' in the Blade section

* Added description for getMessage() in Error pages

$exception variable has methods for displaying the message passed by the abort function, which can be useful in Custom HTTP Error Pages. The proposed changes mention this method with an example for blade template under - "Custom HTTP Error Pages" section.

* Update queries.md

MariaDB already support JSON functions. refer [here](https://mariadb.com/kb/en/mariadb/json-functions/)

* Update queries.md

* Update errors.md

* Update errors.md

* Document Eloquent\Builder::withCount() aliasing support

Documents the feature added by laravel/framework#15279

* tweak formatting

* update example

* document csrf

* clear up wording

* Fixes syntax error

minor syntax error in docs

* Adding getForeignKey rename to upgrade guide

* move docs

* document customization

* Update views.md

* Corrected wrong example code (in sync with master)

The master branch has updated the docs, making the same changes in 5.4

https://github.com/laravel/docs/blob/master/eloquent-relationships.md#many-to-many

* Fix React anchor link. Updated to #react to match section heading

* Update v5.4 Upgrade Guide

Currently the Upgrade guide references a change in the API to
relations where the name of the `getForeignKey` method has changed
to `getForeignKeyName`  In reviewing the code and API docs this
doesn't seem to actually be true.

Example (https://laravel.com/api/5.4/Illuminate/Database/Eloquent/Relations/BelongsTo.html)

This commit removes the seemingly false reference.

* Document Collection::isNotEmpty() method

Documents the feature added by laravel/framework#16797

* Document Collection::containsStrict() method

Documents the feature added by laravel/framework#14657

Also updates the Collection::contains() documentation to outline its behavior and where they differ.

* Document Collection::median() and Collection::mode() methods

Documents the features added by laravel/framework#14305

I also changed the Collection::avg() documentation with the same code snippet to better demonstrate where they differ since they all are related. Since they can be confusing to understand, I also added reference links to Wikipedia to each one.

* [5.4] Document Collection::uniqueStrict() method

Documents the feature added by laravel/framework#14661

Also updates the Collection::unique() documentation to outline its behavior and where they differ.

* [5.4] Document Collection::tap() method

Documents the feature added by laravel/framework#17756

* [5.4] Sync Eloquent\Collection available methods

* Fix reference to getMessage in exception

* Improvements to collections documentation

* Correct example for sending markdown slack attachements

* Update use statement

https://github.com/laravel/laravel/blob/master/app/Providers/AuthServiceProvider.php#L6

* Update scheduling.md file

I feel like the '/path/to/artisan' is a bit confusing a better use of words would be 'path-to-your-project'.

I also found out there are some more people thinking like me:
https://laracasts.com/discuss/channels/laravel/pathtoartisan-where-it-is?page=1

* add notes on laravel version scheme

* Clarifies tests namespace change

Makes clear the composer.json's change is required even for those who skip the "Running Laravel 5.3 & 5.4 Tests In A Single Application" section.

* [5.4] Change user_id to unsigned integer

In the session database table, user_id should be an unsigned integer.

*           add docs for running dusk on travis and circleci

* fix

* Semantic Versioning paragraph small typo fix.

* tweak wording

*     fix CircleCI formatting

* Update facades.md

* Update facades.md

* Added `deleteFileAfterSend()` back in the docs

it is a feature.

* wip

* Document Collection::times() method and flatMap shortcut

* Update collections.md

* Improve the environment configuration documentation

- Moves two general-topic paragraphs from "Retrieving Environment Configuration" sub-section into the main "Environment Configuration" section
- Adds a security note about committing .env files
- Adds a general note to clarify that .env files variables can be overridden by external environment variables
- Makes the "Retrieving Environment Configuration" sub-section linkable
- Adds a tip to the "Determining The Current Environment" sub-section to mention that the APP_ENV variable could be overridden at server-level configuration

* Change word.

* adjust wording and tips

* remove section from docs... php has built in ?? operator

* Clarify 2nd argument of firstOrNew & firstOrCreate

* Update charset/collation

* adjust wording

* Document the Mailable callbacks functionality

* Fix event-fake link

Replace old "mocking-events" to "event-fake" HTML ID

* clean up some documentation

* clarify `optional` and `present`

* clarify note

* Add Documentation for new Blade directives @empty & @Isset

* Adds `assertJsonFragmentMission()` to the list of available testing methods

Signed-off-by: Jesse Schutt <jesse.schutt@zaengle.com>

* Update http-tests.md

* adjust wording

* adjust wording

* @empty checks if $records is empty

* Update query builder JSON docs

* Update homestead.md

* Document "flatten" parameter of mix.copy()

* fix example

* add note
@arjasco arjasco deleted the add-tap-to-collection branch June 25, 2018 19:09
@JosephSilber
Copy link
Member

JosephSilber commented Sep 25, 2020

I came here to weep 😢

Creating a new collection to pass to the callback...

This is just soooo wrong 😞

It's counter-intuitive, and contrary to all other taps.

...because there are some methods which if called on the collection will change the items. eg. the pop method.

Exactly. So if you call a mutating method within tap, you expect the original collection to be mutated.

And if you don't want to mutate the original, you can always clone the collection within your tap.


I just lost over 2 hours tearing my hair out on this. So frustrating 😥

After figuring out what's happening, I had to switch to using pipe, and returning the original instance:

->pipe(function ($collection) use ($mock, $timeout) {
tap($collection)
->mockery_init($mock->mockery_getContainer())
->shouldAllowMockingProtectedMethods()
->shouldReceive('now')
->times(3)
->andReturn(
(clone $timeout)->sub(2, 'minute')->getTimestamp(),
(clone $timeout)->sub(1, 'minute')->getTimestamp(),
$timeout->getTimestamp()
);
return $collection;
})

Really not what you'd expect!


We should change this in the next major version, to pass the collection itself as is.

@driesvints
Copy link
Member

@JosephSilber think I agree. Would you be up for sending in a PR?

@arjasco
Copy link
Contributor Author

arjasco commented Nov 19, 2020

Ooooh, this is old 😀

@JosephSilber I agree, at the time of the implementation my thought process was "The ability to tap into the collection without mutating the original in a chain of method calls". You are right to say this isn't inline with the other "tap" methods or the original Ruby implementation as a matter of fact. I can't say I have used this since submitting the PR, it was useful at the time debugging and partially filtering a large chained collection in an adopted code base, I rarely use plain collections these days.

Surprised it wasn't picked up on quicker 😅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants