======================== LIBRARY RULES ======================== - 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 ======================== CODE SNIPPETS ======================== TITLE: Sanmai Pipeline Development Setup DESCRIPTION: Steps to set up the development environment for contributing to the Sanmai Pipeline library. This includes cloning the repository, installing dependencies, and running tests. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/installation.md#_snippet_5 LANGUAGE: bash CODE: ``` git clone https://github.com/sanmai/pipeline.git cd pipeline composer install make test ``` ---------------------------------------- TITLE: Verify Sanmai Pipeline Installation DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/installation.md#_snippet_3 LANGUAGE: php CODE: ``` map(fn($x) => $x * 2) ->toList(); print_r($result); // Expected output: [2, 4, 6, 8, 10] ``` ---------------------------------------- TITLE: Import Sanmai Pipeline Functions and Classes DESCRIPTION: Demonstrates how to import helper functions and classes from the Sanmai Pipeline library into your PHP code using `use` statements for cleaner syntax. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/installation.md#_snippet_4 LANGUAGE: php CODE: ``` // Import individual functions use function Pipeline\take; use function Pipeline\map; // Or use fully qualified names $pipeline = \Pipeline\take($data); ``` LANGUAGE: php CODE: ``` use Pipeline\Standard; $pipeline = new Standard($data); ``` ---------------------------------------- TITLE: Run Static Analysis for Sanmai Pipeline DESCRIPTION: Instructions for running static analysis tools like PHPStan, Psalm, and Phan on the Sanmai Pipeline codebase to ensure code quality and catch potential errors. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/installation.md#_snippet_6 LANGUAGE: bash CODE: ``` composer require --dev phpstan/phpstan psalm/phar phan/phan make analyze ``` ---------------------------------------- TITLE: Troubleshoot Composer Memory Limits DESCRIPTION: Provides a solution for Composer installation failures caused by memory limits. It shows how to run Composer with an increased memory limit. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/installation.md#_snippet_7 LANGUAGE: bash CODE: ``` COMPOSER_MEMORY_LIMIT=-1 composer require sanmai/pipeline ``` ---------------------------------------- TITLE: Install Pipeline with Composer DESCRIPTION: Installs the Sanmai Pipeline library using Composer, the dependency manager for PHP. The latest version requires PHP 7.4 or above. SOURCE: https://github.com/sanmai/pipeline/blob/main/README.md#_snippet_0 LANGUAGE: bash CODE: ``` composer require sanmai/pipeline ``` ---------------------------------------- TITLE: Install Sanmai Pipeline with Composer DESCRIPTION: Provides the command to install the Sanmai Pipeline library using Composer, the dependency manager for PHP. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/index.md#_snippet_2 LANGUAGE: bash CODE: ``` composer require sanmai/pipeline ``` ---------------------------------------- TITLE: Install Sanmai Pipeline with Composer DESCRIPTION: Adds the Sanmai Pipeline library to your project using Composer. This is the primary method for integrating the library into your PHP application. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/installation.md#_snippet_0 LANGUAGE: bash CODE: ``` composer require sanmai/pipeline ``` ---------------------------------------- TITLE: PHP RunningVariance Merging Example DESCRIPTION: Shows how to merge `RunningVariance` instances, which is useful for combining statistics from different data sources or processing steps. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/api/statistics.md#_snippet_2 LANGUAGE: PHP CODE: ``` // Merge stats from two different sources $stats1 = take($source1)->finalVariance(); $stats2 = take($source2)->finalVariance(); $combinedStats = new RunningVariance($stats1, $stats2); ``` ---------------------------------------- TITLE: Streaming Data from Files and Arrays DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/advanced/best-practices.md#_snippet_0 LANGUAGE: php CODE: ``` // 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(); ``` ---------------------------------------- TITLE: Composer Version Constraints for Sanmai Pipeline DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/installation.md#_snippet_1 LANGUAGE: json CODE: ``` { "require": { "sanmai/pipeline": "^6.0" } } ``` LANGUAGE: json CODE: ``` { "require": { "sanmai/pipeline": "6.11.0" } } ``` LANGUAGE: json CODE: ``` { "require": { "sanmai/pipeline": "dev-main" } } ``` ---------------------------------------- TITLE: PHP Pagination Function DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/basic-usage.md#_snippet_14 LANGUAGE: php CODE: ``` 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] ``` ---------------------------------------- TITLE: PHP Pipeline Chaining and Mutability Example DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/index.md#_snippet_0 LANGUAGE: PHP CODE: ``` $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] ``` ---------------------------------------- TITLE: Check PHP Version Requirement DESCRIPTION: Command to verify the installed PHP version on your system. The Sanmai Pipeline library requires PHP 8.2.0 or higher. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/installation.md#_snippet_8 LANGUAGE: bash CODE: ``` php -v // Must be 8.2.0 or higher ``` ---------------------------------------- TITLE: PHP Pipeline Data Transformation Example DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/README.md#_snippet_1 LANGUAGE: PHP CODE: ``` 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) ``` ---------------------------------------- TITLE: Common Pattern: Processing a Collection (PHP) DESCRIPTION: An example demonstrating a common use case: processing a collection of records (e.g., orders) to filter, transform, and aggregate data. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/basic-usage.md#_snippet_12 LANGUAGE: php CODE: ``` 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 ``` ---------------------------------------- TITLE: PHP Pipeline runningVariance() Example DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/api/statistics.md#_snippet_1 LANGUAGE: PHP CODE: ``` $stats = null; $processedData = take([1, 2, 3, 4, 5]) ->runningVariance($stats) ->map(fn($x) => $x * 2) ->toList(); echo $stats->getMean(); // 3.0 ``` ---------------------------------------- TITLE: Update Composer DESCRIPTION: Command to update Composer to its latest version. Keeping Composer updated can resolve various installation and dependency management issues. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/installation.md#_snippet_9 LANGUAGE: bash CODE: ``` composer self-update ``` ---------------------------------------- TITLE: Map with Generator Function DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/README.md#_snippet_17 LANGUAGE: php CODE: ``` $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; }); ``` ---------------------------------------- TITLE: Include Composer Autoloader in PHP DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/installation.md#_snippet_2 LANGUAGE: php CODE: ``` require_once 'vendor/autoload.php'; ``` ---------------------------------------- TITLE: PHP Pipeline: Basic Operations and Data Merging DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/index.md#_snippet_1 LANGUAGE: php CODE: ``` 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] ``` ---------------------------------------- TITLE: PHP Pipeline finalVariance() Example DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/api/statistics.md#_snippet_0 LANGUAGE: PHP CODE: ``` 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); ``` ---------------------------------------- TITLE: PHP Filtering with Strict Mode DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/reference/changelog.md#_snippet_0 LANGUAGE: PHP CODE: ``` // 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, ''] ``` ---------------------------------------- TITLE: PHP Pipeline: Method Chaining and Operation Types DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/index.md#_snippet_5 LANGUAGE: php CODE: ``` $pipeline ->filter() // Returns $this ->map() // Returns $this ->chunk(100) // Returns $this ->flatten() // Returns $this ->reduce(); // Terminal operation, returns a value ``` ---------------------------------------- TITLE: Reduce Pipeline to Single Value with reduce() or fold() (PHP) DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/basic-usage.md#_snippet_11 LANGUAGE: php CODE: ``` 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 ``` ---------------------------------------- TITLE: Grouping Associative Arrays by Key Pattern (PHP) DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/cookbook/associative-arrays.md#_snippet_5 LANGUAGE: php CODE: ``` $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] // ] ``` ---------------------------------------- TITLE: Get Pipeline Iterator (getIterator) DESCRIPTION: Returns an iterator for the pipeline, allowing manual control or use within foreach loops. This method implements the IteratorAggregate interface for flexible iteration. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/api/collection.md#_snippet_2 LANGUAGE: php CODE: ``` // 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(); } ``` ---------------------------------------- TITLE: Preserving Types with Pipeline filter() DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/generics.md#_snippet_2 LANGUAGE: php CODE: ``` $pipeline = fromValues('hello', 'world')->filter(fn($s) => strlen($s) > 4); // Result: list ``` ---------------------------------------- TITLE: Transforming Types with Pipeline map() DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/generics.md#_snippet_3 LANGUAGE: php CODE: ``` $pipeline = fromArray(['a' => 1])->map(fn($n) => "Number: $n"); // Result: array ``` ---------------------------------------- TITLE: PHP Pipeline for API Response Error Handling DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/advanced/complex-pipelines.md#_snippet_3 LANGUAGE: php CODE: ``` 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'], // ] ``` ---------------------------------------- TITLE: Inferring Pipeline Types with fromValues and fromArray DESCRIPTION: 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`. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/generics.md#_snippet_0 LANGUAGE: php CODE: ``` use function Pipeline\fromArray; use function Pipeline\fromValues; $strings = fromValues('hello', 'world'); // Inferred: Standard $numbers = fromArray(['a' => 1, 'b' => 2]); // Inferred: Standard ``` ---------------------------------------- TITLE: Pipeline Max/Min and Constructor DESCRIPTION: Methods for finding maximum and minimum values, and details about the pipeline constructor. SOURCE: https://github.com/sanmai/pipeline/blob/main/README.md#_snippet_9 LANGUAGE: APIDOC CODE: ``` 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(). ``` ---------------------------------------- TITLE: Sanmai Pipeline Entry Point Functions DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/README.md#_snippet_2 LANGUAGE: APIDOC CODE: ``` 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;` ``` ---------------------------------------- TITLE: PHP ProductImportHelper Unit Tests DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/cookbook/testable-pipelines.md#_snippet_3 LANGUAGE: php CODE: ``` 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)); } } ``` ---------------------------------------- TITLE: PHP Product Import Helper Methods DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/cookbook/testable-pipelines.md#_snippet_1 LANGUAGE: php CODE: ``` 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']); } } ``` ---------------------------------------- TITLE: Create Pipeline from Array (PHP) DESCRIPTION: Demonstrates initializing a pipeline from a PHP array using the Standard constructor, the take() helper, or the fromArray() helper function. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/basic-usage.md#_snippet_0 LANGUAGE: php CODE: ``` 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]); ``` ---------------------------------------- TITLE: PHP Data Model for Product DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/cookbook/testable-pipelines.md#_snippet_0 LANGUAGE: php CODE: ``` final class Product { public function __construct( public readonly string $sku, public readonly string $name, public readonly float $price ) {} } ``` ---------------------------------------- TITLE: Map with Initial Generator DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/README.md#_snippet_18 LANGUAGE: php CODE: ``` $pipeline = new \Pipeline\Standard(); $pipeline->map(function () { yield $this->foo; yield $this->bar; }); ``` ---------------------------------------- TITLE: PHP: Compose Multiple Helpers for Order Processing DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/cookbook/testable-pipelines.md#_snippet_5 LANGUAGE: PHP CODE: ``` 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(...)); } } ``` ---------------------------------------- TITLE: Create Empty Pipeline and Append Data (PHP) DESCRIPTION: Demonstrates creating an empty pipeline instance and subsequently adding data to it using the append() method. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/basic-usage.md#_snippet_3 LANGUAGE: php CODE: ``` $pipeline = new Standard(); $pipeline->append([1, 2, 3]); ``` ---------------------------------------- TITLE: First-Class Callable Syntax DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/api/creation.md#_snippet_9 LANGUAGE: php CODE: ``` // 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(...)); ``` ---------------------------------------- TITLE: Chaining Pipeline Operations DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/advanced/best-practices.md#_snippet_2 LANGUAGE: php CODE: ``` // 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(); ``` ---------------------------------------- TITLE: Create Pipeline from Iterable (PHP) DESCRIPTION: Shows how to create pipelines from various iterable sources, including generators, iterators, and file objects, promoting lazy processing. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/basic-usage.md#_snippet_1 LANGUAGE: php CODE: ``` 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); ``` ---------------------------------------- TITLE: Create Pipeline from Individual Values (PHP) DESCRIPTION: Illustrates using the fromValues() helper function to create a pipeline from a sequence of individual arguments. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/basic-usage.md#_snippet_2 LANGUAGE: php CODE: ``` use function Pipeline\fromValues; $pipeline = fromValues(1, 2, 3, 4, 5); ``` ---------------------------------------- TITLE: Common Pattern: Working with Files (PHP) DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/basic-usage.md#_snippet_13 LANGUAGE: php CODE: ``` 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(); ``` ---------------------------------------- TITLE: PHP: Test Product Importer Sequence Contract DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/cookbook/testable-pipelines.md#_snippet_4 LANGUAGE: PHP CODE: ``` // 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); } } ``` ---------------------------------------- TITLE: Standard Constructor DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/api/creation.md#_snippet_0 LANGUAGE: php CODE: ``` 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; }); ``` ---------------------------------------- TITLE: Unpack with Callback Arguments DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/README.md#_snippet_20 LANGUAGE: php CODE: ``` $pipeline->map(function () { yield [-1, [10, 20], new DateTime()]; }); $pipeline->unpack(function ($a, array $b, \DateTime ...$dates) { // and so on }); ``` ---------------------------------------- TITLE: Legacy Callable Syntax DESCRIPTION: Shows the older, legacy syntax for passing callables to pipeline methods, including string callables and array callables for object and static methods. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/api/creation.md#_snippet_10 LANGUAGE: php CODE: ``` // String callables (older style) $pipeline->cast('intval'); // Array callables (older style) $pipeline->map([$object, 'method']); // Static method array (older style) $pipeline->filter(['ClassName', 'staticMethod']); ``` ---------------------------------------- TITLE: prepend() Method DESCRIPTION: The `prepend()` method adds elements from an iterable to the beginning of the current pipeline, returning the modified pipeline instance. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/api/creation.md#_snippet_7 LANGUAGE: php CODE: ``` $pipeline = take([3, 4])->prepend([1, 2]); // Results in [1, 2, 3, 4] ``` ---------------------------------------- TITLE: Pipeline Creation Methods DESCRIPTION: Methods for creating new pipeline instances from various sources like iterables, arrays, values, generator functions, or by combining multiple iterables. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/reference/method-index.md#_snippet_0 LANGUAGE: APIDOC CODE: ``` 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. ``` ---------------------------------------- TITLE: zip() Helper Function DESCRIPTION: 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`. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/api/creation.md#_snippet_4 LANGUAGE: php CODE: ``` 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]] ``` ---------------------------------------- TITLE: Pipeline Utility Methods DESCRIPTION: Miscellaneous utility methods for pipeline operations, including random selection, zipping, and stream conversion. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/reference/method-index.md#_snippet_6 LANGUAGE: APIDOC CODE: ``` 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. ``` ---------------------------------------- TITLE: PHP: Test with Partial Mocks DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/cookbook/testable-pipelines.md#_snippet_6 LANGUAGE: PHP CODE: ``` $helper = $this->getMockBuilder(ProductImportHelper::class) ->setConstructorArgs([$realDatabase]) ->onlyMethods(['isNewProduct']) // Only mock this method ->getMock(); $helper->method('isNewProduct')->willReturn(true); // Other methods use real implementation ``` ---------------------------------------- TITLE: PHP Pipeline: Creation Methods and Chaining DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/index.md#_snippet_3 LANGUAGE: php CODE: ``` 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); ``` ---------------------------------------- TITLE: PHP Product Importer Workflow DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/cookbook/testable-pipelines.md#_snippet_2 LANGUAGE: php CODE: ``` 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(...)); } } ``` ---------------------------------------- TITLE: fromValues() Helper Function DESCRIPTION: The `fromValues()` helper function creates a pipeline from a sequence of individual values passed as arguments. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/api/creation.md#_snippet_3 LANGUAGE: php CODE: ``` use function Pipeline\fromValues; $pipeline = fromValues(1, 'a', true); ``` ---------------------------------------- TITLE: Prepend and Unshift Elements to Pipeline (PHP) DESCRIPTION: 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(). SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/quickstart/basic-usage.md#_snippet_8 LANGUAGE: php CODE: ``` 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] ``` ---------------------------------------- TITLE: take() Helper Function DESCRIPTION: The `take()` helper function creates a pipeline from one or more iterables. It can accept a single iterable or multiple iterables to be concatenated. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/api/creation.md#_snippet_1 LANGUAGE: php CODE: ``` 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] ``` ---------------------------------------- TITLE: PHP: Create Pipeline with take() DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/api/helpers.md#_snippet_1 LANGUAGE: php CODE: ``` use function Pipeline\take; // From a single array $pipeline = take([1, 2, 3]); // From multiple sources $pipeline = take([1, 2], new ArrayIterator([3, 4])); ``` ---------------------------------------- TITLE: unshift() Method DESCRIPTION: The `unshift()` method prepends individual values to the beginning of the current pipeline, returning the modified pipeline instance. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/api/creation.md#_snippet_8 LANGUAGE: php CODE: ``` $pipeline = take([3, 4])->unshift(1, 2); // Results in [1, 2, 3, 4] ``` ---------------------------------------- TITLE: PHP: Create Pipeline with fromValues() DESCRIPTION: 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. SOURCE: https://github.com/sanmai/pipeline/blob/main/docs/api/helpers.md#_snippet_3 LANGUAGE: php CODE: ``` use function Pipeline\fromValues; $pipeline = fromValues(1, 'a', true); ``` ---------------------------------------- TITLE: Type Safety and Static Analysis in PHP Pipelines DESCRIPTION: Illustrates the library's generic type tracking capabilities. It shows how type safety is maintained through method chaining like `map` and `cast`, and how static analyzers correctly infer type correctness or detect errors when class signatures change. SOURCE: https://github.com/sanmai/pipeline/blob/main/README.md#_snippet_32 LANGUAGE: php CODE: ``` class Foo { public function __construct( public int $n, ) {} public function bar(): string { return "{$this->n}\n"; } } $pipeline = Pipeline\take(['a' => 1, 'b' => 2, 'c' => 3]) ->map(fn(int $n): int => $n * 2) ->cast(fn(int $n): Foo => new Foo($n)); foreach ($pipeline as $value) { echo $value->bar(); } $pipeline = Pipeline\take(['a' => 1, 'b' => 2, 'c' => 3]); $pipeline->map(fn(int $n): int => $n * 2); $pipeline->cast(fn(int $n): FooB => new FooB($n)); foreach ($pipeline as $value) { echo $value->bar(); } ``` LANGUAGE: php CODE: ``` class Foo { public function __construct( public string $n, ) {} public function baz(): string { return "{$this->n}\n"; } } ```