DEV Community

Cover image for Get What You Want: Using PHP Collections to easily filter and manipulate data. 😎
Matt Sparks
Matt Sparks

Posted on

Get What You Want: Using PHP Collections to easily filter and manipulate data. 😎

You've worked with APIs, right? You make a request, you get some data back, and you do something with it. Pretty standard stuff. This tutorial will show you how you can use the power of PHP collections to easily get the data you want.

What are PHP collections? Simply put: a collection is a class that allows us to easily work with arrays.

For this tutorial, we'll be using the tightenco/collect package. This package allows us to use Laravel Collections without the entire framework.

GitHub logo tightenco / collect

A Collections-only split from Laravel's Illuminate Support

Travis Status for tightenco/collect

Collect - Illuminate Collections

Import Laravel's Collections into non-Laravel packages easily, without needing to require the entire Illuminate\Support package. (Why not pull Illuminate\Support in framework-agnostic packages)

Written by Taylor Otwell as a part of Laravel's Illuminate/Support package, Collect is just the code from Support needed in order to use Collections on their own.

Lovingly split by Matt Stauffer for Tighten Co., with a kick in the butt to finally do it from @assertchris.

Installation

With Composer:

composer require tightenco/collect

Development

If you are a developer working on Collect and you're tasked with upgrading it to mirror a new version of Laravel, run ./upgrade.sh from the root directory. You can pass a parameter to target a specific Laravel version (e.g. ./upgrade.sh 5.7.10) or, if you don't pass a parameter, the script will find the latest tagged release and run against that.

The upgrader will pull…

Data for this tutorial was provided by the OMDb API.

Rather than embed the data, you can view it here.

A Simple Example

Before we get into parsing our movie data, let's do a quick example. In this example, we'll grab the first and last item in an array.

use Tightenco\Collect\Support\Collection;

$simpsons = ['Homer', 'Marge', 'Bart', 'Lisa', 'Maggie'];
$c = new Collection($simpsons);

echo $c->first(); // Homer
echo $c->last();  // Maggie

Pretty easy, right? We have an array which we use to make a new Collection instance. From there we use the first() and last() methods to grab "Homer" and "Maggie."

Getting Started

First, we need to first use Composer to pull in our Collection package.

composer require tightenco/collect

Now for each example, we need to include our dependencies and do a little setup.

<?php

require 'vendor/autoload.php';

use Tightenco\Collect\Support\Collection;

$json = file_get_contents(__DIR__ . '/data.json');
$movies = json_decode($json, true);
$c = new Collection($movies);

Collection Methods

The Collection package provides us with a ton of great methods we can use to manipulate our data. Since there are ~110 methods, I won't be going over each one. Instead, I'll highlight a few and explain their functionality.

.map()

The map() function loops through the data and passes each item to the given callback. You are then able to return the item to create a new collection. Below we'll create a new collection that contains only each film's title.

$titles = $c->map(function ($movie) {
    return $movie['Title'];
});

Result:

['The Matrix', 'Blade Runner', 'The Fifth Element', 'Escape From New York']

You're not limited to just returning a single value. Let's create a collection that includes each film along with the date of release.

$release = $c->map(function ($movie) {
    return [$movie['Title'] => [
        'releaseDate' => $movie['Released']
    ]];
});

Result:

[
    'The Matrix' => ['releaseDate' => '31 Mar 1999'],
    'Blade Runner' => ['releaseDate' => '25 Jun 1982'],
    'The Fifth Element' => ['releaseDate' => '09 May 1997'],
    'Escape From New York' => ['releaseDate' => '10 Jul 1981']            
]

Now, let's format the date.

$release = $c->map(function ($movie) {
    return [$movie['Title'] => [
        'releaseDate' => date('F d, Y', strtotime($movie['Released']))
    ]];
});

Result:

[
    'The Matrix' => ['releaseDate' => 'March 31, 1999'],
    'Blade Runner' => ['releaseDate' => 'June 25, 1982'],
    'The Fifth Element' => ['releaseDate' => 'May 09, 1997'],
    'Escape From New York' => ['releaseDate' => 'July 10, 1981']            
]

Side note: if this were a real project I would probably use PHP's DateTime or Carbon to format the date.

.filter()

The filter() method, well, filters the data. Any items that pass a given test will be returned. In the example below, we return any movie whose "Metascore" is at least 70.

$metascore = $c->filter(function ($movie) {
    return $movie['Metascore'] >= 70;
});

Result:

[
    [
        'Title' => 'The Matrix'
        ...
    ], 
    [
        'Title' => 'Blade Runner'
        ...
    ],     
    [
        'Title' => 'Escape From New York'
        ...
    ]   
]

.sum()

The .sum() method is handy when you want to total values. In this example, I use the map() method to return each movie's runtime and then total them to see how long it would take to watch all four films.

$runtime = $c->map(function ($movie) {
    /**
     * Breakdown:
     *
     * 1. Remove " min" from the string.
     * 2. Cast the string to an integer so we can add them
     */
    return (int) str_replace(' min', '', $movie['Runtime']);
})->sum();

Result:

478

.count()

Like .sum(), .count() is a very simple method that can really come in handy when you want to know how many items are in your collection.

$c->count(); // 4

Further Reading

There are ~106 other methods available with this specific package. I encourage you to read the documentation.

Laravel's Collection package isn't the only game in town. Doctrine has a great one and there are many others availble, too! Go find one you like!

Also, Adam Wathan has a great book called Refactoring to Collections that I highly recommend.

[Full disclosure, I'm not being compensated in any way for linking to this book. I just think it's great. That said, Adam, if you're reading this and would like me to become a paid endorser, just get in touch 😆]

Latest comments (0)