A few days ago I discovered I was copy/pasting the same few lines of code in a few places, and if you know me you know that I loathe copy/pasta code.
The problem I had to solve was simple. I had to display data in a variable number of columns. Seems simple enough, not anything anyone has not done before. Here is a simplified version of the code I was using:
<div class="container">
@foreach($collection->chunk(ceil($collectionOfData->count() / $columnCount)) as $columnData)
<div class="column">
@foreach($columnData as $dataToDisplay)
<p>{{ $dataToDisplay }}</p>
@endforeach
</div>
@endforeach
</div>
Its ugly, but it gets the job done. Now I can deal with isolated ugly code, but when I have to re-use ugly code I start to have problems. I figured, I am re-using this code often enough that it might deserve its own macro. Here is what I came up with:
/**
* Splits the collection into a number of pieces.
*
* @param int $pieces
* @param bool $preserveKeys
* @return Collection
*/
Collection::macro('divideInto', function(int $pieces, bool $preserveKeys = true): Collection
{
/** @var Collection $this */
return $this
->chunk(ceil($this->count() / $pieces))
->map(function(Collection $chunk) use ($preserveKeys) {
return $preserveKeys ? $chunk : $chunk->values();
});
});
This does more or less the same thing as what was described above, except I added some flexibility into the mix. Lets go through it line by line.
- The first line (after the PHPDoc, of course) defines the
divideInto()
macro and the inputs it will use,$pieces
and$preserveKeys
. - The next is a simple PHPDoc that helps your IDE. Your IDE does not know the scope that
$this
will run in, so it simply says that "$this
is a Collection". - The line that starts with
->chunk
is pretty straightforward. It "divides" the collection into the number of pieces the user is requesting. - The last lines in the macro are just a tiny bit more complicated. If
$preserveKeys
has been set to false, it will reset all of the keys in all of the new collection chunks.
Here is a quick example of it being used in its most basic form:
Here is an example of it being used, telling it not to preserve the array keys:
So to wrap it all up, lets re-write that code from above with this new macro!
<div class="container">
@foreach($collection->divideInto($columnCount) as $columnData)
<div class="column">
@foreach($columnData as $dataToDisplay)
<p>{{ $dataToDisplay }}</p>
@endforeach
</div>
@endforeach
</div>