1. Go to this page and download the library: Download resoul/data-reader library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
resoul / data-reader example snippets
use DataReader\Config\BaseConfig;
class ValidatedUserConfig extends BaseConfig
{
public function __construct()
{
// Multiple validators
$this->addValidator(function($item) {
return isset($item['email']) && filter_var($item['email'], FILTER_VALIDATE_EMAIL);
});
$this->addValidator(function($item) {
return isset($item['age']) && $item['age'] >= 18;
});
// Field mapping
$this->setFieldMapping([
0 => 'name',
1 => 'email',
2 => 'age',
3 => 'country'
]);
}
public function configureItem($item): ?array
{
$mapped = $this->mapFields($item);
// Skip invalid items
if (!$this->validateItem($mapped)) {
return null;
}
return [
'name' => ucwords(strtolower($mapped['name'])),
'email' => strtolower($mapped['email']),
'age' => (int)$mapped['age'],
'country' => strtoupper($mapped['country']),
'is_adult' => $mapped['age'] >= 18
];
}
public function configureFirstItem($item)
{
return false; // Skip headers
}
}
class MultiStepConfig implements ConfigInterface
{
private array $processors = [];
public function addProcessor(callable $processor): self
{
$this->processors[] = $processor;
return $this;
}
public function configureItem($item): array
{
$result = $item;
foreach ($this->processors as $processor) {
$result = $processor($result);
if ($result === null) {
break; // Skip this item
}
}
return $result;
}
public function configureFirstItem($item)
{
return false;
}
}
// Usage
$config = new MultiStepConfig();
$config->addProcessor(function($item) {
// Step 1: Clean data
return array_map('trim', $item);
})
->addProcessor(function($item) {
// Step 2: Validate
return filter_var($item[1], FILTER_VALIDATE_EMAIL) ? $item : null;
})
->addProcessor(function($item) {
// Step 3: Transform
return [
'name' => $item[0],
'email' => strtolower($item[1]),
'created' => date('Y-m-d H:i:s')
];
});
class StreamingConfig extends BaseConfig
{
private int $processed = 0;
private int $memoryLimit;
public function __construct(int $memoryLimitMB = 128)
{
$this->memoryLimit = $memoryLimitMB * 1024 * 1024;
}
public function configureItem($item): array
{
$this->processed++;
// Memory management
if ($this->processed % 1000 === 0) {
$usage = memory_get_usage(true);
if ($usage > $this->memoryLimit) {
gc_collect_cycles();
error_log("Memory usage: " . round($usage / 1024 / 1024, 2) . "MB after processing {$this->processed} items");
}
}
return $this->processItem($item);
}
private function processItem($item): array
{
// Your processing logic here
return [
'id' => $item[0],
'data' => $item[1],
'processed_at' => time()
];
}
}
use DataReader\Resource\Resource;
use DataReader\ResourceInterface;
use DataReader\ConfigInterface;
class PaginatedApiResource extends Resource implements ResourceInterface
{
private string $baseUrl;
private int $perPage;
private array $headers;
public function __construct(string $baseUrl, int $perPage = 100, array $headers = [])
{
$this->baseUrl = $baseUrl;
$this->perPage = $perPage;
$this->headers = $headers;
}
public function apply(ConfigInterface $config): array
{
$allItems = [];
$page = 1;
do {
$url = $this->baseUrl . "?page={$page}&per_page={$this->perPage}";
$response = $this->makeRequest($url);
$data = json_decode($response, true);
if (empty($data['items'])) {
break;
}
foreach ($data['items'] as $item) {
$processed = $config->configureItem($item);
if ($processed !== null) {
$allItems[] = $processed;
}
}
$page++;
} while (count($data['items']) === $this->perPage);
$this->setData($allItems);
return $this->getData();
}
private function makeRequest(string $url): string
{
$context = stream_context_create([
'http' => [
'method' => 'GET',
'header' => implode("\r\n", $this->headers)
]
]);
$result = file_get_contents($url, false, $context);
if ($result === false) {
throw new ResourceException("Failed to fetch data from: {$url}");
}
return $result;
}
public function setData($data): void
{
$this->data = $data;
}
public function getData(): array
{
return $this->data ?? [];
}
}
use PHPUnit\Framework\TestCase;
use DataReader\Reader;
use DataReader\Resource\ArrayData;
use DataReader\Output\Json;
class ReaderTest extends TestCase
{
public function testBasicDataProcessing(): void
{
$data = [
['John', '[email protected]', '30'],
['Jane', '[email protected]', '25']
];
$config = new class implements ConfigInterface {
public function configureItem($item): array {
return [
'name' => $item[0],
'email' => $item[1],
'age' => (int)$item[2]
];
}
public function configureFirstItem($item) {
return $this->configureItem($item);
}
};
$reader = new Reader(
new ArrayData($data),
new Json(),
$config
);
$result = $reader->run();
$decoded = json_decode($result, true);
$this->assertCount(2, $decoded);
$this->assertEquals('John', $decoded[0]['name']);
$this->assertEquals(30, $decoded[0]['age']);
}
}
// Solution: Use chunked processing
ini_set('memory_limit', '512M');
class ChunkedFileProcessor
{
public function processFile(string $filename, int $chunkSize = 1000): void
{
$handle = fopen($filename, 'r');
$chunk = [];
$count = 0;
while (($line = fgetcsv($handle)) !== false) {
$chunk[] = $line;
$count++;
if ($count >= $chunkSize) {
$this->processChunk($chunk);
$chunk = [];
$count = 0;
gc_collect_cycles();
}
}
if (!empty($chunk)) {
$this->processChunk($chunk);
}
fclose($handle);
}
private function processChunk(array $chunk): void
{
$reader = new Reader(
new ArrayData($chunk),
new Json(),
new MyConfig()
);
echo $reader->run();
}
}
class EncodingAwareConfig extends BaseConfig
{
private string $encoding;
public function __construct(string $encoding = 'UTF-8')
{
$this->encoding = $encoding;
}
public function configureItem($item): array
{
// Convert encoding
foreach ($item as $key => $value) {
if (is_string($value)) {
$item[$key] = mb_convert_encoding($value, 'UTF-8', $this->encoding);
}
}
return $this->processItem($item);
}
}
DataReader\Factory\ReaderFactory;
// Quick setup with factory methods
$reader = ReaderFactory::createCsvReader('data.csv');
// Or manual setup with custom configuration
use DataReader\Reader;
use DataReader\Resource\File;
use DataReader\Resource\File\CSV;
use DataReader\Output\Json;
use DataReader\Config\BaseConfig;
class UserDataConfig extends BaseConfig
{
public function configureItem($item): array
{
return [
'id' => (int)$item[0],
'name' => trim($item[1]),
'email' => strtolower($item[2]),
'age' => (int)$item[3],
'created_at' => new DateTime($item[4])
];
}
public function configureFirstItem($item)
{
// Skip header row
return false;
}
}
$reader = new Reader();
$reader->resource(new File('users.csv', new CSV()));
$reader->config(new UserDataConfig());
$reader->output(new Json(JSON_PRETTY_PRINT));
try {
$processedData = $reader->run();
echo $processedData; // JSON output
} catch (\DataReader\Exception\DataReaderException $e) {
echo "Error: " . $e->getMessage();
}
$reader = new Reader($resource, $output, $config);
// or use fluent interface
$reader->resource($resource)
->config($config)
->output($output)
->run();
use DataReader\Config\BaseConfig;
class ProductConfig extends BaseConfig
{
public function __construct()
{
// Set up field mapping
$this->setFieldMapping([
0 => 'name',
1 => 'price',
2 => 'category'
]);
// Add validators
$this->addValidator(function($item) {
return isset($item['price']) && $item['price'] > 0;
});
}
public function configureItem($item): array
{
$mapped = $this->mapFields($item);
if (!$this->validateItem($mapped)) {
throw new InvalidArgumentException('Invalid item data');
}
return [
'name' => trim($mapped['name']),
'price' => (float)$mapped['price'],
'category' => strtoupper($mapped['category']),
'in_stock' => $mapped['price'] > 0
];
}
public function configureFirstItem($item)
{
// Skip header or process first row
return false;
}
}
use DataReader\Reader;
use DataReader\Resource\File;
use DataReader\Resource\File\CSV;
use DataReader\Output\Json;
class UserConfig implements \DataReader\ConfigInterface
{
public function configureItem($item): array
{
return [
'id' => (int)$item[0],
'name' => trim($item[1]),
'email' => filter_var($item[2], FILTER_VALIDATE_EMAIL),
'created_at' => new DateTime($item[3])
];
}
public function configureFirstItem($item)
{
// Skip header row
return false;
}
}
$reader = new Reader(
new File('users.csv', new CSV()),
new Json(JSON_PRETTY_PRINT),
new UserConfig()
);
try {
$users = $reader->run();
echo $users; // Pretty-printed JSON
} catch (\DataReader\Exception\ResourceException $e) {
echo "File error: " . $e->getMessage();
}
use DataReader\Resource\File\JSON;
$reader = new Reader(
new File('data.json', new JSON()),
new Json(),
new DataConfig()
);
$data = $reader->run();
use DataReader\Resource\File\XML;
// XML with custom item tag
$reader = new Reader(
new File('products.xml', new XML('product')), // item tag = 'product'
new Json(),
new ProductConfig()
);
$products = $reader->run();
use DataReader\Resource\ArrayData;
use DataReader\Config\BaseConfig;
class ProductConfig extends BaseConfig
{
public function __construct()
{
// Set up field mapping
$this->setFieldMapping([
'product_name' => 'name',
'price' => 'price',
'quantity' => 'stock'
]);
// Add validation
$this->addValidator(function($item) {
return isset($item['price']) && $item['price'] > 0;
});
}
public function configureItem($item): array
{
$mapped = $this->mapFields($item);
if (!$this->validateItem($mapped)) {
return null; // Skip invalid items
}
return [
'name' => $mapped['name'],
'price' => (float)$mapped['price'],
'in_stock' => (int)$mapped['stock'] > 0
];
}
public function configureFirstItem($item)
{
return $this->configureItem($item);
}
}
$rawData = [
['product_name' => 'Laptop', 'price' => '999.99', 'quantity' => '5'],
['product_name' => 'Mouse', 'price' => '29.99', 'quantity' => '0'],
['product_name' => 'Invalid', 'price' => '-10', 'quantity' => '1'] // Will be skipped
];
$reader = new Reader(
new ArrayData($rawData),
new Json(),
new ProductConfig()
);
$products = $reader->run();
use DataReader\Output\XML;
$reader = new Reader(
new File('data.csv', new CSV()),
new XML('products', 'product'), // root: products, items: product
new ProductConfig()
);
$xmlOutput = $reader->run();
echo $xmlOutput;
// <products>
// <product>
// <name>Laptop</name>
// <price>999.99</price>
// </product>
// </products>
use DataReader\Output\CSV as CsvOutput;
$reader = new Reader(
new File('data.json', new JSON()),
new CsvOutput('|', '"'), // Custom delimiter and enclosure
new DataConfig()
);
$csvOutput = $reader->run();
use DataReader\Resource\Resource;
use DataReader\ResourceInterface;
use DataReader\ConfigInterface;
use DataReader\Exception\ResourceException;
class DatabaseResource extends Resource implements ResourceInterface
{
private \PDO $connection;
private string $query;
public function __construct(\PDO $connection, string $query)
{
$this->connection = $connection;
$this->query = $query;
}
public function apply(ConfigInterface $config): array
{
try {
$stmt = $this->connection->prepare($this->query);
$stmt->execute();
$items = [];
$isFirst = true;
while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
if ($isFirst) {
$firstItem = $config->configureFirstItem($row);
if ($firstItem !== false) {
$items[] = $firstItem;
}
$isFirst = false;
} else {
$items[] = $config->configureItem($row);
}
}
$this->setData($items);
return $this->getData();
} catch (\PDOException $e) {
throw new ResourceException('Database error: ' . $e->getMessage());
}
}
public function setData($data): void
{
$this->data = $data;
}
public function getData(): array
{
return $this->data ?? [];
}
}
// Usage
$pdo = new PDO($dsn, $user, $pass);
$reader = new Reader(
new DatabaseResource($pdo, 'SELECT * FROM users'),
new Json(),
new UserConfig()
);
use DataReader\Resource\FileInterface;
use DataReader\ConfigInterface;
use DataReader\Exception\ResourceException;
class ExcelFormat implements FileInterface
{
public function read($handle, ConfigInterface $config): array
{
// Example with PhpSpreadsheet (worksheet = $spreadsheet->getActiveSheet();
$data = $worksheet->toArray();
$items = [];
foreach ($data as $index => $row) {
if ($index === 0) {
$firstItem = $config->configureFirstItem($row);
if ($firstItem !== false) {
$items[] = $firstItem;
}
} else {
$items[] = $config->configureItem($row);
}
}
return $items;
} finally {
unlink($tempFile);
}
}
}
use DataReader\Output\Output;
use DataReader\OutputInterface;
class HTMLOutput extends Output implements OutputInterface
{
private string $tableClass;
public function __construct(string $tableClass = 'table')
{
$this->tableClass = $tableClass;
}
public function items($items): string
{
if (empty($items)) {
return '<p>No data available</p>';
}
$html = "<table class=\"{$this->tableClass}\">\n";
// Header
$headers = array_keys($items[0]);
$html .= "<thead><tr>\n";
foreach ($headers as $header) {
$html .= "<th>" . htmlspecialchars($header) . "</th>\n";
}
$html .= "</tr></thead>\n";
// Body
$html .= "<tbody>\n";
foreach ($items as $item) {
$html .= "<tr>\n";
foreach ($item as $value) {
$html .= "<td>" . htmlspecialchars((string)$value) . "</td>\n";
}
$html .= "</tr>\n";
}
$html .= "</tbody>\n</table>";
return $html;
}
}
// For large datasets, process in chunks
class ChunkedConfig extends BaseConfig
{
private int $processed = 0;
private int $chunkSize;
public function __construct(int $chunkSize = 1000)
{
$this->chunkSize = $chunkSize;
}
public function configureItem($item): ?array
{
if ($this->processed++ % $this->chunkSize === 0) {
// Trigger garbage collection every chunk
gc_collect_cycles();
}
return $this->processItem($item);
}
}
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.