=============== LIBRARY RULES =============== From library maintainers: - Lazy evaluation works only with generators and iterators - Chain methods fluently as the Pipeline returns the same instance - Use stream() to ensure lazy evaluation paths - Avoid iterator_to_array() - use toList() or toAssoc() instead - Remember that pipelines cannot be rewound after consumption ### Sanmai Pipeline Development Setup Source: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/installation.md Steps to set up the development environment for contributing to the Sanmai Pipeline library. This includes cloning the repository, installing dependencies, and running tests. ```bash git clone https://github.com/sanmai/pipeline.git cd pipeline composer install make test ``` -------------------------------- ### Verify Sanmai Pipeline Installation Source: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/installation.md A simple PHP script to confirm that the Sanmai Pipeline library is installed correctly and functional. It demonstrates basic usage of the `take` and `map` functions. ```php map(fn($x) => $x * 2) ->toList(); print_r($result); // Expected output: [2, 4, 6, 8, 10] ``` -------------------------------- ### Import Sanmai Pipeline Functions and Classes Source: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/installation.md Demonstrates how to import helper functions and classes from the Sanmai Pipeline library into your PHP code using `use` statements for cleaner syntax. ```php // Import individual functions use function Pipeline\take; use function Pipeline\map; // Or use fully qualified names $pipeline = \Pipeline\take($data); ``` ```php use Pipeline\Standard; $pipeline = new Standard($data); ``` -------------------------------- ### Run Static Analysis for Sanmai Pipeline Source: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/installation.md Instructions for running static analysis tools like PHPStan, Psalm, and Phan on the Sanmai Pipeline codebase to ensure code quality and catch potential errors. ```bash composer require --dev phpstan/phpstan psalm/phar phan/phan make analyze ``` -------------------------------- ### Troubleshoot Composer Memory Limits Source: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/installation.md Provides a solution for Composer installation failures caused by memory limits. It shows how to run Composer with an increased memory limit. ```bash COMPOSER_MEMORY_LIMIT=-1 composer require sanmai/pipeline ``` -------------------------------- ### Install Pipeline with Composer Source: https://github.com/sanmai/pipeline/blob/main/README.md Installs the Sanmai Pipeline library using Composer, the dependency manager for PHP. The latest version requires PHP 7.4 or above. ```bash composer require sanmai/pipeline ``` -------------------------------- ### Install Sanmai Pipeline with Composer Source: https://github.com/sanmai/pipeline/blob/main/docs/index.md Provides the command to install the Sanmai Pipeline library using Composer, the dependency manager for PHP. ```bash composer require sanmai/pipeline ``` -------------------------------- ### Install Sanmai Pipeline with Composer Source: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/installation.md Adds the Sanmai Pipeline library to your project using Composer. This is the primary method for integrating the library into your PHP application. ```bash composer require sanmai/pipeline ``` -------------------------------- ### PHP RunningVariance Merging Example Source: https://github.com/sanmai/pipeline/blob/main/docs/api/statistics.md Shows how to merge `RunningVariance` instances, which is useful for combining statistics from different data sources or processing steps. ```PHP // Merge stats from two different sources $stats1 = take($source1)->finalVariance(); $stats2 = take($source2)->finalVariance(); $combinedStats = new RunningVariance($stats1, $stats2); ``` -------------------------------- ### Streaming Data from Files and Arrays Source: https://github.com/sanmai/pipeline/blob/main/docs/advanced/best-practices.md Demonstrates how to use the Pipeline library to process data efficiently by treating inputs as streams. Prefer iterators and generators for large datasets to minimize memory usage, especially when starting from files or large arrays. ```php // Good: Streaming from a file $result = take(new SplFileObject('data.csv')) ->map('str_getcsv') ->toList(); // Good: Forcing a stream from a large array $result = take($largeArray) ->stream() ->filter(fn($user) => $user['active']) ->toList(); ``` -------------------------------- ### Composer Version Constraints for Sanmai Pipeline Source: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/installation.md Specifies how to manage version constraints for the Sanmai Pipeline library in your Composer project's `composer.json` file. This ensures compatibility and allows for controlled updates. ```json { "require": { "sanmai/pipeline": "^6.0" } } ``` ```json { "require": { "sanmai/pipeline": "6.11.0" } } ``` ```json { "require": { "sanmai/pipeline": "dev-main" } } ``` -------------------------------- ### PHP Pagination Function Source: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/basic-usage.md Demonstrates a PHP function `getPage` that calculates and retrieves a specific page of data from an iterable source. It takes the data, desired page number, and items per page as input, returning an array of items for that page. The example shows how to use the function to get the second page of a range of numbers. ```php function getPage(iterable $data, int $page, int $perPage = 10): array { $offset = ($page - 1) * $perPage; return take($data) ->slice($offset, $perPage) ->toList(); } $page2 = getPage(range(1, 100), 2, 10); // [11, 12, 13, 14, 15, 16, 17, 18, 19, 20] ``` -------------------------------- ### PHP Pipeline Chaining and Mutability Example Source: https://github.com/sanmai/pipeline/blob/main/docs/index.md Demonstrates the mutable nature of Pipeline\Standard instances and how chaining operations affects shared references. It illustrates initializing pipelines, assigning references, applying transformations, and collecting results. ```PHP $pipelineA = take([1, 2, 3]); $pipelineB = $pipelineA; // $pipelineB now references the same pipeline as $pipelineA $pipelineA->map(fn($x) => $x * 2); // This modifies the shared pipeline // Both $pipelineA and $pipelineB will now yield [2, 4, 6] var_dump($pipelineB->toList()); // Output: [2, 4, 6] // Example of chaining pipelines $firstPipeline = take(range(1, 5))->map(fn($n) => $n * 10); $secondPipeline = new \Pipeline\Standard($firstPipeline); $secondPipeline->filter(fn($n) => $n > 20); // The second pipeline now processes the output of the first var_dump($secondPipeline->toList()); // Output: [30, 40, 50] ``` -------------------------------- ### Check PHP Version Requirement Source: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/installation.md Command to verify the installed PHP version on your system. The Sanmai Pipeline library requires PHP 8.2.0 or higher. ```bash php -v // Must be 8.2.0 or higher ``` -------------------------------- ### PHP Pipeline Data Transformation Example Source: https://github.com/sanmai/pipeline/blob/main/README.md Demonstrates chaining various operations on an iterable using the Sanmai Pipeline library. This includes taking an initial iterable, zipping it with other iterables, unpacking elements, mapping values (one-to-one and one-to-many), casting elements, filtering, and reducing the pipeline to a single value. ```PHP use function Pipeline\take; use function Pipeline\map; // iterable corresponds to arrays, generators, iterators // we use an array here simplicity sake $iterable = range(1, 3); // wrap the initial iterable with a pipeline $pipeline = take($iterable); // join side by side with other iterables of any type $pipeline->zip( \range(1, 3), map(function () { yield 1; yield 2; yield 3; }) ); // lazily process their elements together $pipeline->unpack(function (int $a, int $b, int $c) { return $a - $b - $c; }); // map one value into several more $pipeline->map(function ($i) { yield pow($i, 2); yield pow($i, 3); }); // simple one-to-one mapper $pipeline->cast(function ($i) { return $i - 1; }); // map into arrays $pipeline->map(function ($i) { yield [$i, 2]; yield [$i, 4]; }); // unpack array into arguments $pipeline->unpack(function ($i, $j) { yield $i * $j; }); // one way to filter $pipeline->map(function ($i) { if ($i > 50) { yield $i; } }); // this uses a filtering iterator from SPL under the hood $pipeline->filter(function ($i) { return $i > 100; }); // reduce to a single value; can be an array or any value $value = $pipeline->fold(0, function ($carry, $item) { // for the sake of convenience the default reducer from the simple // pipeline does summation, just like we do here return $carry + $item; }); var_dump($value); // int(104) ``` -------------------------------- ### Common Pattern: Processing a Collection (PHP) Source: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/basic-usage.md An example demonstrating a common use case: processing a collection of records (e.g., orders) to filter, transform, and aggregate data. ```php use function Pipeline\take; $orders = [ ['id' => 1, 'total' => 100, 'status' => 'paid'], ['id' => 2, 'total' => 200, 'status' => 'pending'], ['id' => 3, 'total' => 150, 'status' => 'paid'], ]; $paidTotal = take($orders) ->filter(fn($order) => $order['status'] === 'paid') ->map(fn($order) => $order['total']) ->reduce(fn($a, $b) => $a + $b); // Result: 250 ``` -------------------------------- ### PHP Pipeline runningVariance() Example Source: https://github.com/sanmai/pipeline/blob/main/docs/api/statistics.md Illustrates the `runningVariance()` intermediate operation, which observes values and calculates statistics without consuming the pipeline. This allows for inspecting statistics at a point in the data flow. ```PHP $stats = null; $processedData = take([1, 2, 3, 4, 5]) ->runningVariance($stats) ->map(fn($x) => $x * 2) ->toList(); echo $stats->getMean(); // 3.0 ``` -------------------------------- ### Update Composer Source: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/installation.md Command to update Composer to its latest version. Keeping Composer updated can resolve various installation and dependency management issues. ```bash composer self-update ``` -------------------------------- ### Map with Generator Function Source: https://github.com/sanmai/pipeline/blob/main/README.md Illustrates using the `map` method with a generator function to process each item in the pipeline. The example shows iterating over payments and yielding each one for further processing. ```php $pipeline->map(function (Customer $customer) { foreach ($customer->allPayments() as $item) { yield $item; } }); // Now process all and every payment $pipeline->map(function (Payment $payment) { return $payment->amount; }); ``` -------------------------------- ### Include Composer Autoloader in PHP Source: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/installation.md Ensures that the library's classes and functions are available by including Composer's autoloader file in your PHP entry point. This is crucial for PSR-4 autoloading. ```php require_once 'vendor/autoload.php'; ``` -------------------------------- ### PHP Pipeline: Basic Operations and Data Merging Source: https://github.com/sanmai/pipeline/blob/main/docs/index.md Demonstrates creating pipelines, chaining operations like filter, map, slice, and reduce, and combining multiple data sources. This example shows how to process a range of numbers, filter for even values, square them, take the first ten, and sum the results. ```php use function Pipeline\take; // This pipeline will: // 1. Take numbers from 1 to 100 // 2. Filter for even numbers // 3. Square each number // 4. Take the first 10 results // 5. Sum the results $result = take(range(1, 100)) ->filter(fn($n) => $n % 2 === 0) ->map(fn($n) => $n ** 2) ->slice(0, 10) ->reduce(fn($a, $b) => $a + $b); // Returns 220 // Example with multiple data sources $pipeline = take([1, 2, 3]) ->append([4, 5, 6]) ->prepend([0]) ->map(fn($x) => $x * 2) ->toList(); // Returns [0, 2, 4, 6, 8, 10, 12] ``` -------------------------------- ### PHP Pipeline finalVariance() Example Source: https://github.com/sanmai/pipeline/blob/main/docs/api/statistics.md Demonstrates the usage of the `finalVariance()` terminal operation to calculate comprehensive statistics on pipeline data. It shows basic usage, handling specific fields, skipping non-numeric values, and continuing calculations from existing statistics. ```PHP use Pipeline\Helper\RunningVariance; // Basic statistics $stats = take([1, 2, 3, 4, 5])->finalVariance(); echo $stats->getCount(); // 5 echo $stats->getMean(); // 3.0 echo $stats->getVariance(); // 2.5 echo $stats->getStandardDeviation(); // ~1.58 echo $stats->getMin(); // 1.0 echo $stats->getMax(); // 5.0 // Statistics for a specific field $stats = take($users)->finalVariance(fn($user) => $user['age']); // Handling mixed data (skip non-numeric values) $stats = take(['1', 'abc', 2, null, 3.5]) ->finalVariance(fn($x) => is_numeric($x) ? (float)$x : null); echo $stats->getCount(); // 3 (only numeric values counted) // Continuing from existing statistics $initialStats = take($firstBatch)->finalVariance(); $combinedStats = take($secondBatch)->finalVariance(null, $initialStats); ``` -------------------------------- ### PHP Filtering with Strict Mode Source: https://github.com/sanmai/pipeline/blob/main/docs/reference/changelog.md Demonstrates the `filter()` method in the Pipeline library, showing the difference between default filtering (removes falsy values) and strict mode filtering (removes only null and false). This example highlights how to enable stricter data cleaning. ```PHP // Old behavior (removes all falsy values) $result = take([0, '', false, null])->filter()->toList(); // [] // New strict mode (removes only null and false) $result = take([0, '', false, null])->filter(strict: true)->toList(); // [0, ''] ``` -------------------------------- ### PHP Pipeline: Method Chaining and Operation Types Source: https://github.com/sanmai/pipeline/blob/main/docs/index.md Explains how non-terminal operations return the pipeline instance for chaining, while terminal operations consume the pipeline and return a final result. This section lists examples of both types of operations. ```php $pipeline ->filter() // Returns $this ->map() // Returns $this ->chunk(100) // Returns $this ->flatten() // Returns $this ->reduce(); // Terminal operation, returns a value ``` -------------------------------- ### Reduce Pipeline to Single Value with reduce() or fold() (PHP) Source: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/basic-usage.md Reduces the pipeline to a single aggregated value by applying a callback function iteratively. `reduce()` starts with the first element, while `fold()` allows an initial carry value. ```php use function Pipeline\take; // Sum all values $sum = take([1, 2, 3, 4, 5])->reduce(fn($a, $b) => $a + $b); // 15 // Calculate a product with an initial value $product = take([1, 2, 3, 4, 5]) ->fold(1, fn($carry, $item) => $carry * $item); // 120 ``` -------------------------------- ### Grouping Associative Arrays by Key Pattern (PHP) Source: https://github.com/sanmai/pipeline/blob/main/docs/cookbook/associative-arrays.md Groups elements of an associative array based on a pattern in their keys. This example uses `tuples()` and `fold()` to iterate through the array and build a nested structure based on key prefixes. ```php $data = [ 'user_name' => 'Alice', 'user_email' => 'alice@example.com', 'order_id' => 123, 'order_total' => 99.99 ]; $grouped = take($data) ->tuples() ->fold([], function($groups, $tuple) { [$key, $value] = $tuple; $prefix = explode('_', $key)[0]; $groups[$prefix][$key] = $value; return $groups; }); // Result: // [ // 'user' => ['user_name' => 'Alice', 'user_email' => 'alice@example.com'], // 'order' => ['order_id' => 123, 'order_total' => 99.99] // ] ``` -------------------------------- ### Get Pipeline Iterator (getIterator) Source: https://github.com/sanmai/pipeline/blob/main/docs/api/collection.md Returns an iterator for the pipeline, allowing manual control or use within foreach loops. This method implements the IteratorAggregate interface for flexible iteration. ```php // Using foreach $pipeline = take(['a' => 1, 'b' => 2]); foreach ($pipeline as $key => $value) { echo "$key: $value\n"; } // Manual iteration $iterator = take([1, 2, 3])->getIterator(); while ($iterator->valid()) { echo $iterator->current(); $iterator->next(); } ``` -------------------------------- ### Preserving Types with Pipeline filter() Source: https://github.com/sanmai/pipeline/blob/main/docs/generics.md Explains that the `filter()` method preserves the existing types of elements within a pipeline, only reducing their count. The example shows a pipeline resulting in `list` after filtering. ```php $pipeline = fromValues('hello', 'world')->filter(fn($s) => strlen($s) > 4); // Result: list ``` -------------------------------- ### Transforming Types with Pipeline map() Source: https://github.com/sanmai/pipeline/blob/main/docs/generics.md Illustrates how `map()` and `cast()` methods are used to transform values and potentially change their types. Static analysis tools accurately track these type changes, as shown in the example transforming an integer to a string. ```php $pipeline = fromArray(['a' => 1])->map(fn($n) => "Number: $n"); // Result: array ``` -------------------------------- ### PHP Pipeline for API Response Error Handling Source: https://github.com/sanmai/pipeline/blob/main/docs/advanced/complex-pipelines.md A practical example processing simulated API responses, handling potential request failures and JSON decoding errors. It collects valid data and logs errors separately, demonstrating robust error management in data ingestion. ```php use function Pipeline\take; // Simulate API responses with potential failures $apiResponses = [ ['url' => '/users/1', 'data' => '{"id":1,"name":"Alice"}'], ['url' => '/users/2', 'data' => 'invalid json'], ['url' => '/users/3', 'data' => '{"id":3,"name":"Charlie"}'], ['url' => '/users/4', 'data' => null], // Failed request ]; // Process with error collection $validUsers = []; $errors = []; take($apiResponses) ->map(function($response) use (&$errors) { if ($response['data'] === null) { $errors[] = ['url' => $response['url'], 'error' => 'Request failed']; return null; } $decoded = json_decode($response['data'], true); if (json_last_error() !== JSON_ERROR_NONE) { $errors[] = ['url' => $response['url'], 'error' => 'Invalid JSON']; return null; } return $decoded; }) ->filter() // Remove nulls ->each(function($user) use (&$validUsers) { $validUsers[] = $user; }); // $validUsers: // [ // ['id' => 1, 'name' => 'Alice'], // ['id' => 3, 'name' => 'Charlie'], // ] // // $errors: // [ // ['url' => '/users/2', 'error' => 'Invalid JSON'], // ['url' => '/users/4', 'error' => 'Request failed'], // ] ``` -------------------------------- ### Inferring Pipeline Types with fromValues and fromArray Source: https://github.com/sanmai/pipeline/blob/main/docs/generics.md Demonstrates how Pipeline automatically infers generic types for keys and values when creating pipelines using `fromValues()` or `fromArray()`. Examples show inferred types like `Standard` and `Standard`. ```php use function Pipeline\fromArray; use function Pipeline\fromValues; $strings = fromValues('hello', 'world'); // Inferred: Standard $numbers = fromArray(['a' => 1, 'b' => 2]); // Inferred: Standard ``` -------------------------------- ### Pipeline Max/Min and Constructor Source: https://github.com/sanmai/pipeline/blob/main/README.md Methods for finding maximum and minimum values, and details about the pipeline constructor. ```APIDOC max() - Finds the highest value in the pipeline. - Alias: max min() - Finds the lowest value in the pipeline. - Alias: min __construct(initialIterator = null) - Constructor for the Pipeline class. - Can be provided with an optional initial iterator. - Used internally by functions like take(). ``` -------------------------------- ### Sanmai Pipeline Entry Point Functions Source: https://github.com/sanmai/pipeline/blob/main/README.md Provides an overview of the core functions used to create and manage pipelines. All entry points are designed to return an instance of the pipeline, facilitating chained operations. Usage typically involves importing the specific function. ```APIDOC API Entry Points: All entry points always return an instance of the pipeline. map(callback: callable = null): - Takes an optional initial callback, which must not require any arguments if provided. - Otherwise, works identically to an instance method. - Usage: `use function Pipeline\map;` take(iterable, ...iterables): - Accepts any iterables, including arrays. - Joins them together in succession to form a pipeline. - Usage: `use function Pipeline\take;` fromArray(array): - Initializes a pipeline with the provided array. - Usage: `use function Pipeline\fromArray;` zip(iterable, ...iterables): - Takes one or more iterables. - Transposes them together, creating a pipeline of zipped elements. - Usage: `use function Pipeline\zip;` ``` -------------------------------- ### PHP ProductImportHelper Unit Tests Source: https://github.com/sanmai/pipeline/blob/main/docs/cookbook/testable-pipelines.md Demonstrates how to unit test individual methods of the ProductImportHelper. It uses PHPUnit and mocks dependencies like DatabaseConnection to isolate and verify the helper's logic without external side effects. ```php use PHPUnit\Framework\TestCase; class ProductImportHelperTest extends TestCase { private ProductImportHelper $helper; protected function setUp(): void { $this->helper = new ProductImportHelper($this->createMock(DatabaseConnection::class)); } public function testIsValidSku(): void { $this->assertTrue($this->helper->isValidSku(['sku' => 'PROD-12345'])); $this->assertFalse($this->helper->isValidSku(['sku' => 'INVALID'])); $this->assertFalse($this->helper->isValidSku(['sku' => 'PROD-123'])); // Too short } public function testNormalizeData(): void { $input = ['sku' => ' PROD-12345 ', 'name' => ' Widget ', 'price' => '9.99']; $expected = ['sku' => 'PROD-12345', 'name' => 'Widget', 'price' => 9.99]; $this->assertEquals($expected, $this->helper->normalizeData($input)); } } ``` -------------------------------- ### PHP Product Import Helper Methods Source: https://github.com/sanmai/pipeline/blob/main/docs/cookbook/testable-pipelines.md Contains the specific logic for each step of the product import process, such as validation, normalization, and database checks. It depends on a DatabaseConnection and implements methods like isCompleteRow, normalizeData, isValidSku, isNewProduct, and createProductEntity. ```php class ProductImportHelper { public function __construct(private readonly DatabaseConnection $db) {} public function isCompleteRow(array $row): bool { return isset($row['sku'], $row['name'], $row['price']); } public function normalizeData(array $row): array { $row['sku'] = trim($row['sku']); $row['name'] = trim($row['name']); $row['price'] = (float) $row['price']; return $row; } public function isValidSku(array $row): bool { // SKUs must be "PROD-12345" format return (bool) preg_match('/^PROD-\d{5}$/', $row['sku']); } public function isNewProduct(array $row): bool { // SIDE EFFECT: Database query return !$this->db->productExists($row['sku']); } public function createProductEntity(array $row): Product { return new Product($row['sku'], $row['name'], $row['price']); } } ``` -------------------------------- ### Create Pipeline from Array (PHP) Source: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/basic-usage.md Demonstrates initializing a pipeline from a PHP array using the Standard constructor, the take() helper, or the fromArray() helper function. ```php use Pipeline\Standard; use function Pipeline\take; use function Pipeline\fromArray; // Using the constructor $pipeline = new Standard([1, 2, 3]); // Using the take() helper $pipeline = take([1, 2, 3]); // Using the fromArray() helper $pipeline = fromArray([1, 2, 3]); ``` -------------------------------- ### PHP Data Model for Product Source: https://github.com/sanmai/pipeline/blob/main/docs/cookbook/testable-pipelines.md Defines the structure for product data, including SKU, name, and price. It's a simple PHP class with read-only properties, serving as the output for the import process. ```php final class Product { public function __construct( public readonly string $sku, public readonly string $name, public readonly float $price ) {} } ``` -------------------------------- ### Map with Initial Generator Source: https://github.com/sanmai/pipeline/blob/main/README.md Shows how to initialize a pipeline using the `map` method with an initial generator function. This generator does not require arguments and sets the initial data source for the pipeline. ```php $pipeline = new \Pipeline\Standard(); $pipeline->map(function () { yield $this->foo; yield $this->bar; }); ``` -------------------------------- ### PHP: Compose Multiple Helpers for Order Processing Source: https://github.com/sanmai/pipeline/blob/main/docs/cookbook/testable-pipelines.md Illustrates how to compose multiple specialized helper classes within a single orchestrator class for complex workflows. This approach enhances modularity and allows for cleaner separation of concerns, where each helper handles a specific aspect of the processing pipeline. ```PHP class OrderProcessor { public function __construct( private readonly ValidationHelper $validator, private readonly PricingHelper $pricing, private readonly InventoryHelper $inventory ) {} public function process(iterable $orders): iterable { return take($orders) ->filter($this->validator->isValid(...)) ->map($this->pricing->calculateTotals(...)) ->filter($this->inventory->isInStock(...)) ->map($this->createOrder(...)); } } ``` -------------------------------- ### Create Empty Pipeline and Append Data (PHP) Source: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/basic-usage.md Demonstrates creating an empty pipeline instance and subsequently adding data to it using the append() method. ```php $pipeline = new Standard(); $pipeline->append([1, 2, 3]); ``` -------------------------------- ### First-Class Callable Syntax Source: https://github.com/sanmai/pipeline/blob/main/docs/api/creation.md Demonstrates the use of PHP 8.1+ first-class callable syntax for methods like `cast`, `map`, and `filter`, offering cleaner and more type-safe code. ```php // Modern syntax (PHP 8.1+) $pipeline = take(['1', '2', '3']) ->cast(intval(...)) ->toList(); // Works with any function $pipeline = take(['hello', 'world']) ->map(strtoupper(...)) ->toList(); // Works with object methods $helper = new DataProcessor(); $pipeline = take($data) ->filter($helper->isValid(...)) ->map($helper->transform(...)); // Works with static methods $pipeline = take($users) ->filter(User::isActive(...)) ->map(User::normalize(...)); ``` -------------------------------- ### Chaining Pipeline Operations Source: https://github.com/sanmai/pipeline/blob/main/docs/advanced/best-practices.md Illustrates the best practice of chaining operations in a single, fluent sequence for improved readability and efficiency. Avoid breaking the chain into multiple steps, as this can lead to unnecessary intermediate variables and reduced performance. ```php // Good: A single, readable chain $result = take($data) ->filter($predicate) ->map($transformer) ->toList(); // Bad: Breaking the chain creates unnecessary intermediate variables $filtered = take($data)->filter($predicate)->toList(); $result = take($filtered)->map($transformer)->toList(); ``` -------------------------------- ### Create Pipeline from Iterable (PHP) Source: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/basic-usage.md Shows how to create pipelines from various iterable sources, including generators, iterators, and file objects, promoting lazy processing. ```php use function Pipeline\take; // From a generator function generateNumbers() { for ($i = 1; $i <= 5; $i++) { yield $i; } } $pipeline = take(generateNumbers()); // From an iterator $iterator = new ArrayIterator([1, 2, 3]); $pipeline = take($iterator); // From a file $file = new SplFileObject('data.txt'); $pipeline = take($file); ``` -------------------------------- ### Create Pipeline from Individual Values (PHP) Source: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/basic-usage.md Illustrates using the fromValues() helper function to create a pipeline from a sequence of individual arguments. ```php use function Pipeline\fromValues; $pipeline = fromValues(1, 2, 3, 4, 5); ``` -------------------------------- ### Common Pattern: Working with Files (PHP) Source: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/basic-usage.md Illustrates common file processing tasks, such as counting lines matching a pattern in a log file or parsing CSV data, using pipelines for efficient handling. ```php use function Pipeline\take; // Count error lines in a log file $errorCount = take(new SplFileObject('app.log')) ->filter(fn($line) => str_contains($line, 'ERROR')) ->count(); // Process a CSV file $data = take(new SplFileObject('data.csv')) ->map(str_getcsv(...)) ->filter(fn($row) => count($row) === 3) ->toList(); ``` -------------------------------- ### PHP: Test Product Importer Sequence Contract Source: https://github.com/sanmai/pipeline/blob/main/docs/cookbook/testable-pipelines.md Demonstrates testing the exact sequence of operations in a ProductImporter using PHPUnit mocks. It verifies that specific helper methods are called in the expected order and with the correct arguments, ensuring the pipeline logic is sound and side effects are controlled. ```PHP // tests/ProductImporterTest.php class ProductImporterTest extends TestCase { public function testImportSequenceIsCorrect(): void { $helper = $this->createMock(ProductImportHelper::class); // Define the EXACT sequence we expect $helper->expects($this->once()) ->method('isCompleteRow') ->willReturn(true); $helper->expects($this->once()) ->method('normalizeData') ->willReturnArgument(0); $helper->expects($this->once()) ->method('isValidSku') ->willReturn(true); $helper->expects($this->once()) ->method('isNewProduct') ->willReturn(true); $helper->expects($this->once()) ->method('createProductEntity') ->willReturn(new Product('PROD-12345', 'Test', 99.99)); $importer = new ProductImporter($helper); // Execute the pipeline $results = iterator_to_array($importer->import([ ['sku' => 'PROD-12345', 'name' => 'Test Product', 'price' => '99.99'] ])); $this->assertCount(1, $results); } public function testSkipsInvalidSku(): void { $helper = $this->createMock(ProductImportHelper::class); $helper->expects($this->once())->method('isCompleteRow')->willReturn(true); $helper->expects($this->once())->method('normalizeData')->willReturnArgument(0); $helper->expects($this->once())->method('isValidSku')->willReturn(false); // This is the key: isNewProduct should NEVER be called for invalid SKUs $helper->expects($this->never())->method('isNewProduct'); $helper->expects($this->never())->method('createProductEntity'); $importer = new ProductImporter($helper); $results = iterator_to_array($importer->import([ ['sku' => 'INVALID', 'name' => 'Test', 'price' => '99.99'] ])); $this->assertEmpty($results); } } ``` -------------------------------- ### Standard Constructor Source: https://github.com/sanmai/pipeline/blob/main/docs/api/creation.md The `Standard` class is the primary entry point for creating a pipeline. It can be initialized with an optional iterable data source, such as an array, iterator, or generator. ```php use Pipeline\Standard; // Create an empty pipeline $pipeline = new Standard(); // Create a pipeline from an array $pipeline = new Standard([1, 2, 3]); // Create a pipeline from a generator $pipeline = new Standard(function () { yield 1; yield 2; }); ``` -------------------------------- ### Unpack with Callback Arguments Source: https://github.com/sanmai/pipeline/blob/main/README.md Illustrates using the `unpack()` method with a callback that accepts arguments directly, unpacking array elements and objects into distinct parameters. This simplifies handling complex data structures passed through the pipeline. ```php $pipeline->map(function () { yield [-1, [10, 20], new DateTime()]; }); $pipeline->unpack(function ($a, array $b, \DateTime ...$dates) { // and so on }); ``` -------------------------------- ### Legacy Callable Syntax Source: https://github.com/sanmai/pipeline/blob/main/docs/api/creation.md Shows the older, legacy syntax for passing callables to pipeline methods, including string callables and array callables for object and static methods. ```php // String callables (older style) $pipeline->cast('intval'); // Array callables (older style) $pipeline->map([$object, 'method']); // Static method array (older style) $pipeline->filter(['ClassName', 'staticMethod']); ``` -------------------------------- ### prepend() Method Source: https://github.com/sanmai/pipeline/blob/main/docs/api/creation.md The `prepend()` method adds elements from an iterable to the beginning of the current pipeline, returning the modified pipeline instance. ```php $pipeline = take([3, 4])->prepend([1, 2]); // Results in [1, 2, 3, 4] ``` -------------------------------- ### Pipeline Creation Methods Source: https://github.com/sanmai/pipeline/blob/main/docs/reference/method-index.md Methods for creating new pipeline instances from various sources like iterables, arrays, values, generator functions, or by combining multiple iterables. ```APIDOC Pipeline Creation Methods: new Standard() - Creates a new pipeline instance. - Returns: A new pipeline instance. take(iterable1, iterable2, ...) - Creates a pipeline from one or more iterables. - Parameters: - iterable1, iterable2, ...: One or more iterables to form the pipeline. - Returns: A new pipeline instance. fromArray(array) - Creates a pipeline from an array. - Parameters: - array: The array to convert into a pipeline. - Returns: A new pipeline instance. fromValues(value1, value2, ...) - Creates a pipeline from individual values. - Parameters: - value1, value2, ...: Individual values to form the pipeline. - Returns: A new pipeline instance. map(generatorFunction) - Creates a pipeline from a generator function. - Parameters: - generatorFunction: A function that yields values. - Returns: A new pipeline instance. zip(iterable1, iterable2, ...) - Combines multiple iterables into a pipeline of tuples. - Parameters: - iterable1, iterable2, ...: Iterables to zip together. - Returns: A new pipeline instance containing tuples of elements from input iterables. ``` -------------------------------- ### zip() Helper Function Source: https://github.com/sanmai/pipeline/blob/main/docs/api/creation.md The `zip()` helper function combines multiple iterables into a single pipeline where each element is an array (tuple) containing corresponding elements from the input iterables. Shorter iterables are padded with `null`. ```php use function Pipeline\zip; $names = ['Alice', 'Bob']; $ages = [30, 25]; $result = zip($names, $ages)->toList(); // [['Alice', 30], ['Bob', 25]] $letters = ['a', 'b', 'c']; $numbers = [1, 2]; $result_padded = zip($letters, $numbers)->toList(); // [['a', 1], ['b', 2], ['c', null]] ``` -------------------------------- ### Pipeline Utility Methods Source: https://github.com/sanmai/pipeline/blob/main/docs/reference/method-index.md Miscellaneous utility methods for pipeline operations, including random selection, zipping, and stream conversion. ```APIDOC Pipeline Utility Methods: reservoir(k) - Selects a random subset of k elements from the pipeline using reservoir sampling. - Parameters: - k: The desired size of the random subset. - Returns: A new pipeline containing k randomly selected elements. zip(iterable1, iterable2, ...) - Combines multiple iterables into a pipeline of tuples. - This is a duplicate method, potentially for different contexts or overloads. - Parameters: - iterable1, iterable2, ...: Iterables to zip together. - Returns: A new pipeline containing tuples of elements from input iterables. runningCount() - Counts elements without consuming the pipeline. - Provides a count of elements processed so far. - Returns: A pipeline that yields the running count. stream() - Converts an array-based pipeline to a stream. - Facilitates integration with stream processing libraries or patterns. - Returns: A stream representation of the pipeline. ``` -------------------------------- ### PHP: Test with Partial Mocks Source: https://github.com/sanmai/pipeline/blob/main/docs/cookbook/testable-pipelines.md Shows how to use PHPUnit's `getMockBuilder` to create partial mocks, allowing specific methods to be mocked while letting others use their real implementations. This is useful when you want to test a component's interaction with its dependencies but also leverage some of the component's own logic without mocking. ```PHP $helper = $this->getMockBuilder(ProductImportHelper::class) ->setConstructorArgs([$realDatabase]) ->onlyMethods(['isNewProduct']) // Only mock this method ->getMock(); $helper->method('isNewProduct')->willReturn(true); // Other methods use real implementation ``` -------------------------------- ### PHP Pipeline: Creation Methods and Chaining Source: https://github.com/sanmai/pipeline/blob/main/docs/index.md Illustrates creating pipelines from arrays, using helper functions like `take` and `map`, and processing generators. It also shows chaining operations like `filter`, `map`, and `fold` for data transformation. ```php use Pipeline\Standard; use function Pipeline\take; use function Pipeline\map; // From a variable $pipeline = new Standard($data); // Using the helper function $pipeline = take($data); // From a generator $pipeline = map(function() { yield 1; yield 2; yield 3; }); // Chaining operations $result = $pipeline ->filter($predicate) ->map($transformer) ->fold($initial, $reducer); ``` -------------------------------- ### PHP Product Importer Workflow Source: https://github.com/sanmai/pipeline/blob/main/docs/cookbook/testable-pipelines.md Orchestrates the product import workflow using a pipeline. It takes an iterable of CSV rows, filters and maps them through the helper methods. The pipeline order is critical for correctness, ensuring validation precedes database operations. ```php use function Pipeline\take; class ProductImporter { public function __construct(private readonly ProductImportHelper $helper) {} public function import(iterable $csvRows): iterable { return take($csvRows) ->filter($this->helper->isCompleteRow(...)) ->map($this->helper->normalizeData(...)) ->filter($this->helper->isValidSku(...)) ->filter($this->helper->isNewProduct(...)) // Must come AFTER validation! ->map($this->helper->createProductEntity(...)); } } ``` -------------------------------- ### fromValues() Helper Function Source: https://github.com/sanmai/pipeline/blob/main/docs/api/creation.md The `fromValues()` helper function creates a pipeline from a sequence of individual values passed as arguments. ```php use function Pipeline\fromValues; $pipeline = fromValues(1, 'a', true); ``` -------------------------------- ### Prepend and Unshift Elements to Pipeline (PHP) Source: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/basic-usage.md Adds elements to the beginning of a pipeline, either by prepending the contents of an iterable using prepend(), or by adding individual elements using unshift(). ```php use function Pipeline\take; $result = take([4, 5, 6]) ->prepend([1, 2, 3]) ->toList(); // [1, 2, 3, 4, 5, 6] $result = take([4, 5, 6]) ->unshift(1, 2, 3) ->toList(); // [1, 2, 3, 4, 5, 6] ``` -------------------------------- ### take() Helper Function Source: https://github.com/sanmai/pipeline/blob/main/docs/api/creation.md The `take()` helper function creates a pipeline from one or more iterables. It can accept a single iterable or multiple iterables to be concatenated. ```php use function Pipeline\take; // From a single source $pipeline = take([1, 2, 3]); // From multiple sources $pipeline = take([1, 2], [3, 4]); // Results in [1, 2, 3, 4] ``` -------------------------------- ### PHP: Create Pipeline with take() Source: https://github.com/sanmai/pipeline/blob/main/docs/api/helpers.md Creates a pipeline from one or more iterables. It accepts a primary data source and additional iterables to append to the pipeline. Useful for initializing pipelines with existing data collections. ```php use function Pipeline\take; // From a single array $pipeline = take([1, 2, 3]); // From multiple sources $pipeline = take([1, 2], new ArrayIterator([3, 4])); ``` -------------------------------- ### unshift() Method Source: https://github.com/sanmai/pipeline/blob/main/docs/api/creation.md The `unshift()` method prepends individual values to the beginning of the current pipeline, returning the modified pipeline instance. ```php $pipeline = take([3, 4])->unshift(1, 2); // Results in [1, 2, 3, 4] ``` -------------------------------- ### PHP: Create Pipeline with fromValues() Source: https://github.com/sanmai/pipeline/blob/main/docs/api/helpers.md Creates a pipeline from a sequence of individual values passed as arguments. It allows building a pipeline by directly listing the elements it should contain. ```php use function Pipeline\fromValues; $pipeline = fromValues(1, 'a', true); ```