Lesson 3
Mastering Data Aggregation and Formatting in PHP
Introduction

Welcome to our lesson on mastering data aggregation and data streams with PHP. In this lesson, you'll learn to build a basic sales records aggregator using PHP's associative arrays and classes. Then, we'll extend its functionality to handle more complex operations such as filtering, data aggregation, and formatting. By the end of this session, you'll be proficient in managing and formatting data streams efficiently in PHP.

Starter Task Methods and Their Definitions

To get started, we'll create a simple sales record aggregator in PHP. Here are the methods we'll focus on:

  • public function addSale(string $saleId, float $amount, string $date): void; — Adds or updates a sale record with a unique identifier saleId, amount, and a date in the format "YYYY-MM-DD".

  • public function getSale(string $saleId): ?float; — Retrieves the sale amount associated with the saleId. If the sale does not exist, it returns null.

  • public function deleteSale(string $saleId): bool; — Deletes the sale record with the given saleId. Returns true if the sale was deleted and false if the sale does not exist.

Are these methods clear so far? Great! Let's now look at how we would implement them.

Starter Task Implementation

Here is the complete code for the starter task:

php
1<?php 2 3class SalesAggregator { 4 private $sales = []; 5 6 public function addSale(string $saleId, float $amount, string $date): void { 7 $this->sales[$saleId] = ['amount' => $amount, 'date' => $date]; 8 } 9 10 public function getSale(string $saleId): ?float { 11 if (isset($this->sales[$saleId])) { 12 return $this->sales[$saleId]['amount']; 13 } 14 return null; 15 } 16 17 public function deleteSale(string $saleId): bool { 18 if (isset($this->sales[$saleId])) { 19 unset($this->sales[$saleId]); 20 return true; 21 } 22 return false; 23 } 24} 25 26// Example Usage 27$aggregator = new SalesAggregator(); 28 29// Add sales 30$aggregator->addSale("001", 100.50, "2023-01-01"); 31$aggregator->addSale("002", 200.75, "2023-01-15"); 32 33// Get sale 34$sale = $aggregator->getSale("001"); 35if ($sale !== null) { 36 echo $sale . PHP_EOL; // Output: 100.5 37} 38 39// Delete sale 40echo $aggregator->deleteSale("002") ? 'true' : 'false'; // Output: true 41echo PHP_EOL; 42$sale = $aggregator->getSale("002"); 43if ($sale === null) { 44 echo "Sale not found" . PHP_EOL; // Output: Sale not found 45} 46?>

Explanation:

  • The $sales array stores sale records with saleId as the key and an associative array of amount and date as the value.
  • addSale adds a new sale or updates an existing sale ID.
  • getSale retrieves the amount for a given sale ID or returns null if the sale does not exist.
  • deleteSale removes the sale record for the given sale ID or returns false if the sale does not exist.

Now that we have our basic aggregator, let's extend it to include more advanced functionalities.

Step 1: Implementing the 'Aggregate Sales' Method

We'll create the aggregateSales method:

php
1<?php 2 3class SalesAggregator { 4 private $sales = []; 5 6 public function aggregateSales(float $minAmount = 0): array { 7 $totalSales = 0; 8 $totalAmount = 0.0; 9 foreach ($this->sales as $saleId => $data) { 10 if ($data['amount'] > $minAmount) { 11 $totalSales++; 12 $totalAmount += $data['amount']; 13 } 14 } 15 return [$totalSales, $totalAmount]; 16 } 17 18 public function addSale(string $saleId, float $amount, string $date): void { 19 $this->sales[$saleId] = ['amount' => $amount, 'date' => $date]; 20 } 21} 22 23// Example Usage 24$aggregator = new SalesAggregator(); 25$aggregator->addSale("001", 100.50, "2023-01-01"); 26$aggregator->addSale("002", 200.75, "2023-01-15"); 27 28$result = $aggregator->aggregateSales(50); 29echo "Total Sales: " . $result[0] . ", Total Amount: " . $result[1] . PHP_EOL; 30// Output: Total Sales: 2, Total Amount: 301.25 31?>

This method iterates through the sales and sums those that exceed the minAmount.

Step 2: Implementing the 'Format Sales' Method

Next, we create the formatSales method to output data in plain text format.

php
1<?php 2 3class SalesAggregator { 4 private $sales = []; 5 6 public function formatSales(float $minAmount = 0): string { 7 $output = "Sales:\n"; 8 $statistics = $this->aggregateSales($minAmount); 9 10 foreach ($this->sales as $saleId => $data) { 11 if ($data['amount'] > $minAmount) { 12 $output .= "Sale ID: $saleId, Amount: " . $data['amount'] . ", Date: " . $data['date'] . "\n"; 13 } 14 } 15 16 $output .= "Summary:\nTotal Sales: " . $statistics[0] . ", Total Amount: " . $statistics[1] . "\n"; 17 18 return $output; 19 } 20 21 public function aggregateSales(float $minAmount = 0): array { 22 $totalSales = 0; 23 $totalAmount = 0.0; 24 foreach ($this->sales as $saleId => $data) { 25 if ($data['amount'] > $minAmount) { 26 $totalSales++; 27 $totalAmount += $data['amount']; 28 } 29 } 30 return [$totalSales, $totalAmount]; 31 } 32 33 public function addSale(string $saleId, float $amount, string $date): void { 34 $this->sales[$saleId] = ['amount' => $amount, 'date' => $date]; 35 } 36} 37 38// Example Usage 39$aggregator = new SalesAggregator(); 40$aggregator->addSale("001", 100.50, "2023-01-01"); 41$aggregator->addSale("002", 200.75, "2023-01-15"); 42 43echo $aggregator->formatSales(50) . PHP_EOL; 44// Output: 45// Sales: 46// Sale ID: 001, Amount: 100.5, Date: 2023-01-01 47// Sale ID: 002, Amount: 200.75, Date: 2023-01-15 48// Summary: 49// Total Sales: 2, Total Amount: 301.25 50?>

In this method, we use PHP's simple string concatenation to build the output string for formatted data.

Step 3: Implementing the 'Get Sales in Date Range' Method

Let's implement getSalesInDateRange, which relies on PHP's DateTime objects for date comparison.

php
1<?php 2 3class SalesAggregator { 4 private $sales = []; 5 6 public function getSalesInDateRange(string $startDate, string $endDate): array { 7 $result = []; 8 9 $start = new DateTime($startDate); 10 $end = new DateTime($endDate); 11 12 foreach ($this->sales as $saleId => $data) { 13 $saleDate = new DateTime($data['date']); 14 if ($saleDate >= $start && $saleDate <= $end) { 15 $result[] = [$saleId, $data['amount'], $data['date']]; 16 } 17 } 18 return $result; 19 } 20 21 public function addSale(string $saleId, float $amount, string $date): void { 22 $this->sales[$saleId] = ['amount' => $amount, 'date' => $date]; 23 } 24} 25 26// Example Usage 27$aggregator = new SalesAggregator(); 28$aggregator->addSale("001", 100.50, "2023-01-01"); 29$aggregator->addSale("002", 200.75, "2023-01-15"); 30 31$salesInRange = $aggregator->getSalesInDateRange("2023-01-01", "2023-12-31"); 32foreach ($salesInRange as $sale) { 33 echo "Sale ID: " . $sale[0] . ", Amount: " . $sale[1] . ", Date: " . $sale[2] . PHP_EOL; 34} 35// Output: 36// Sale ID: 001, Amount: 100.5, Date: 2023-01-01 37// Sale ID: 002, Amount: 200.75, Date: 2023-01-15 38?>

In this method, PHP's DateTime class is used to compare dates and ensure accurate filtering of sales records.

Lesson Summary

Congratulations! You've extended a basic PHP sales aggregator to an advanced aggregator, capable of filtering, aggregating, and formatting data using PHP's built-in structures and functions. These skills are crucial for efficiently managing data streams, especially with varying datasets in PHP. Feel free to experiment with similar challenges to reinforce your understanding. Well done!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.