> */ private static array $datasets = []; /** * Holds the withs. * * @var array|string>> */ private static array $withs = []; /** * Sets the given. * * @param Closure|iterable $data */ public static function set(string $name, Closure|iterable $data): void { if (array_key_exists($name, self::$datasets)) { throw new DatasetAlreadyExist($name); } self::$datasets[$name] = $data; } /** * Sets the given "with". * * @param array|string> $with */ public static function with(string $filename, string $description, array $with): void { self::$withs[$filename . '>>>' . $description] = $with; } public static function has(string $filename, string $description): bool { return array_key_exists($filename . '>>>' . $description, self::$withs); } /** * @return Closure|iterable|never * * @throws ShouldNotHappen */ public static function get(string $filename, string $description): Closure|iterable { $dataset = self::$withs[$filename . '>>>' . $description]; $dataset = self::resolve($description, $dataset); if ($dataset === null) { throw ShouldNotHappen::fromMessage('Dataset [%s] not resolvable.'); } return $dataset; } /** * Resolves the current dataset to an array value. * * @param array|string> $dataset * * @return array|null */ public static function resolve(string $description, array $dataset): array|null { /* @phpstan-ignore-next-line */ if (empty($dataset)) { return null; } $dataset = self::processDatasets($dataset); $datasetCombinations = self::getDatasetsCombinations($dataset); $datasetDescriptions = []; $datasetValues = []; foreach ($datasetCombinations as $datasetCombination) { $partialDescriptions = []; $values = []; foreach ($datasetCombination as $datasetCombinationElement) { $partialDescriptions[] = $datasetCombinationElement['label']; // @phpstan-ignore-next-line $values = array_merge($values, $datasetCombinationElement['values']); } $datasetDescriptions[] = implode(' / ', $partialDescriptions); $datasetValues[] = $values; } foreach (array_count_values($datasetDescriptions) as $descriptionToCheck => $count) { if ($count > 1) { $index = 1; foreach ($datasetDescriptions as $i => $datasetDescription) { if ($datasetDescription === $descriptionToCheck) { $datasetDescriptions[$i] .= sprintf(' #%d', $index++); } } } } $namedData = []; foreach ($datasetDescriptions as $i => $datasetDescription) { $namedData[$datasetDescription] = $datasetValues[$i]; } return $namedData; } /** * @param array|string> $datasets * * @return array> */ private static function processDatasets(array $datasets): array { $processedDatasets = []; foreach ($datasets as $index => $data) { $processedDataset = []; if (is_string($data)) { if (!array_key_exists($data, self::$datasets)) { throw new DatasetDoesNotExist($data); } $datasets[$index] = self::$datasets[$data]; } if (is_callable($datasets[$index])) { $datasets[$index] = call_user_func($datasets[$index]); } if ($datasets[$index] instanceof Traversable) { $datasets[$index] = iterator_to_array($datasets[$index]); } // @phpstan-ignore-next-line foreach ($datasets[$index] as $key => $values) { $values = is_array($values) ? $values : [$values]; $processedDataset[] = [ 'label' => self::getDatasetDescription($key, $values), // @phpstan-ignore-line 'values' => $values, ]; } $processedDatasets[] = $processedDataset; } return $processedDatasets; } /** * @param array> $combinations * * @return array>> */ private static function getDatasetsCombinations(array $combinations): array { $result = [[]]; foreach ($combinations as $index => $values) { $tmp = []; foreach ($result as $resultItem) { foreach ($values as $value) { $tmp[] = array_merge($resultItem, [$index => $value]); } } $result = $tmp; } // @phpstan-ignore-next-line return $result; } /** * @param array $data */ private static function getDatasetDescription(int|string $key, array $data): string { $exporter = new Exporter(); if (is_int($key)) { return sprintf('(%s)', $exporter->shortenedRecursiveExport($data)); } return sprintf('data set "%s"', $key); } }