> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fiquela.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Stream\Provider

> Static factory methods for opening data streams from files and strings, plus documentation for each individual stream class.

## Overview

**Namespace:** `FQL\Stream`

`Stream\Provider` opens a data file or an in-memory string and returns a stream object. Each stream implements `Interface\Stream` and exposes a `query()` method that returns a `Query` ready to run against that stream.

You rarely need to call stream classes directly — [`Query\Provider::fromFile()`](/api/query-provider) wraps `Stream\Provider` automatically. Use `Stream\Provider` directly when you need to configure the stream (e.g. set a custom CSV delimiter) before building a query.

***

## `Stream\Provider` static methods

### `fromFile()`

Open a file and return the matching stream object. The format is detected from the file extension unless `$format` is provided.

```php theme={null}
public static function fromFile(string $path, ?Enum\Format $format = null): Interface\Stream
```

<ParamField path="path" type="string" required>
  Absolute or relative path to the data file.
</ParamField>

<ParamField path="format" type="FQL\Enum\Format | null">
  Override the auto-detected format.
</ParamField>

<ResponseField name="returns" type="FQL\Interface\Stream">
  A concrete stream instance (e.g. `Json`, `Csv`, `Xml`).
</ResponseField>

**Throws:** `FileNotFoundException`, `InvalidFormatException`

```php theme={null}
use FQL\Stream\Provider;
use FQL\Enum\Format;

$stream = Provider::fromFile('data/products.json');
$query  = $stream->query();

// Force a format
$stream = Provider::fromFile('data/export', Format::CSV);
```

***

### `fromString()`

Create a stream from an in-memory string. Supported formats: `JSON`, `YAML`, `NEON`.

```php theme={null}
public static function fromString(string $data, Enum\Format $format): Interface\Stream
```

<ParamField path="data" type="string" required>
  The raw string content to parse.
</ParamField>

<ParamField path="format" type="FQL\Enum\Format" required>
  The format of the string content. Must be `Format::JSON`, `Format::YAML`, or `Format::NEON`.
</ParamField>

<ResponseField name="returns" type="FQL\Interface\Stream">
  A stream wrapping the parsed string.
</ResponseField>

**Throws:** `InvalidFormatException` for unsupported formats (e.g. XML, CSV).

```php theme={null}
use FQL\Stream\Provider;
use FQL\Enum\Format;

$json = '{"users": [{"id": 1, "name": "Alice"}]}';

$results = Provider::fromString($json, Format::JSON)
    ->query()
    ->from('users')
    ->execute();
```

***

## Stream classes

Each stream class can also be instantiated directly via its static `open()` method. After obtaining a stream instance, call `->query()` to get a `Query`.

### `Xml`

**Class:** `FQL\Stream\Xml`\
**Formats:** `.xml`

```php theme={null}
public static function open(string $path): Interface\Stream
```

```php theme={null}
use FQL\Stream\Xml;

$query = Xml::open('catalog.xml')
    ->query()
    ->from('catalog.book');
```

<Tip>
  For XML files with non-UTF-8 encoding, call `->setInputEncoding('windows-1250')` on the stream before calling `->query()`.
</Tip>

***

### `Json`

**Class:** `FQL\Stream\Json`\
**Formats:** `.json` (full in-memory parse)

```php theme={null}
public static function open(string $path): Interface\Stream
```

Loads the entire JSON file into memory. Use `JsonStream` for large files.

```php theme={null}
use FQL\Stream\Json;

$query = Json::open('users.json')
    ->query()
    ->from('data.users');
```

***

### `JsonStream`

**Class:** `FQL\Stream\JsonStream`\
**Formats:** `.json` (streaming, lazy)

```php theme={null}
public static function open(string $path): Interface\Stream
```

Streams large JSON files row-by-row without loading the entire file into memory.

```php theme={null}
use FQL\Stream\JsonStream;

$query = JsonStream::open('large-catalog.json')->query();
```

***

### `NDJson`

**Class:** `FQL\Stream\NDJson`\
**Formats:** `.ndjson` (Newline Delimited JSON)

```php theme={null}
public static function open(string $path): Interface\Stream
```

Each line in the file must be a valid JSON object.

```php theme={null}
use FQL\Stream\NDJson;

$query = NDJson::open('events.ndjson')->query();
```

***

### `Csv`

**Class:** `FQL\Stream\Csv`\
**Formats:** `.csv`, `.tsv`

```php theme={null}
public static function open(string $path): Interface\Stream
```

<ParamField path="path" type="string" required>
  Path to the CSV file.
</ParamField>

The CSV reader is built on native PHP `fgetcsv` (no third-party dependency) and accepts the parameters listed below. Defaults are applied when a parameter is omitted.

| Parameter   | Default | Description                                                                                                                       |
| ----------- | ------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `encoding`  | `utf-8` | Source encoding. Non-UTF-8 input is transcoded via a `convert.iconv.<src>/UTF-8` stream filter.                                   |
| `delimiter` | `,`     | Single-character field delimiter.                                                                                                 |
| `enclosure` | `"`     | Single-character field enclosure.                                                                                                 |
| `useHeader` | `1`     | When `1`, the first row is treated as field names. When `0`, rows are emitted as numerically-indexed arrays.                      |
| `bom`       | `0`     | When `1`, the writer emits a UTF-8 BOM. The reader auto-detects UTF-8 / UTF-16 LE/BE / UTF-32 LE/BE BOMs regardless of this flag. |

To use a custom delimiter directly, call `openWithDelimiter()`. For full control over encoding, enclosure, header handling, and BOM, use a FileQuery string.

```php theme={null}
use FQL\Stream\Csv;

// Default comma delimiter
$query = Csv::open('orders.csv')->query();

// Custom delimiter
$query = Csv::openWithDelimiter('orders.tsv', "\t")->query();
```

```php theme={null}
// Via FileQuery string with all parameters
use FQL\Query\Provider;

$query = Provider::fromFileQuery('csv(orders.csv, ";").*');

// Named parameters for non-default encoding, enclosure, and BOM
$query = Provider::fromFileQuery(
    'csv(orders.csv, encoding: "windows-1250", delimiter: ";", enclosure: "\'", bom: "1").*'
);
```

***

### `Yaml`

**Class:** `FQL\Stream\Yaml`\
**Formats:** `.yaml`, `.yml`

```php theme={null}
public static function open(string $path): Interface\Stream
```

```php theme={null}
use FQL\Stream\Yaml;

$query = Yaml::open('config.yaml')->query()->from('services');
```

***

### `Neon`

**Class:** `FQL\Stream\Neon`\
**Formats:** `.neon`

```php theme={null}
public static function open(string $path): Interface\Stream
```

NEON is the configuration format used by the Nette framework.

```php theme={null}
use FQL\Stream\Neon;

$query = Neon::open('config.neon')->query();
```

***

### `Xls`

**Class:** `FQL\Stream\Xls`\
**Formats:** `.xlsx`

```php theme={null}
public static function open(string $path): Interface\Stream
```

Opens an Excel spreadsheet. Only the modern `.xlsx` format (Office Open XML) is supported. Legacy `.xls` (Excel 97–2003 binary format) is no longer supported — convert old files to `.xlsx` first.

```php theme={null}
use FQL\Stream\Xls;

$query = Xls::open('report.xlsx')->query()->from('Sheet1');
```

***

### `Ods`

**Class:** `FQL\Stream\Ods`\
**Formats:** `.ods`

```php theme={null}
public static function open(string $path): Interface\Stream
```

```php theme={null}
use FQL\Stream\Ods;

$query = Ods::open('spreadsheet.ods')->query();
```

***

### `AccessLog`

**Class:** `FQL\Stream\AccessLog`\
**Formats:** `.log`

```php theme={null}
public static function open(string $path): Interface\Stream
```

Reads HTTP server access log files line by line. Each line is parsed according to a predefined profile or a custom Apache `log_format` pattern.

```php theme={null}
use FQL\Stream\AccessLog;

// Default profile: nginx_combined
$query = AccessLog::open('access.log')->query();

// Switch to a different profile before querying
$log = AccessLog::open('access.log');
$log->setFormat('apache_common');
$query = $log->query()->select('host', 'status', 'method')->from('*');
```

**`setFormat(string $format): void`** — Sets the active log profile. Accepts `nginx_combined` (default), `nginx_main`, `apache_combined`, `apache_common`, or `custom` (requires a `setPattern()` call).

**`setPattern(string $pattern): void`** — Sets a custom Apache `log_format` pattern. Only effective when the format is `custom`.

**Predefined profiles:**

| Profile           | Pattern                                                             |
| ----------------- | ------------------------------------------------------------------- |
| `nginx_combined`  | `%h - %u [%t] "%r" %>s %b "%{Referer}i" "%{User-Agent}i"` (default) |
| `nginx_main`      | `%h - %u [%t] "%r" %>s %b`                                          |
| `apache_combined` | `%h %l %u [%t] "%r" %>s %b "%{Referer}i" "%{User-Agent}i"`          |
| `apache_common`   | `%h %l %u [%t] "%r" %>s %b`                                         |

**Special fields in every row:**

| Field    | Type           | Description                                       |
| -------- | -------------- | ------------------------------------------------- |
| `_raw`   | string         | Original unparsed log line                        |
| `_error` | string \| null | `null` on success, error message on parse failure |

<Note>
  `AccessLog` does not support `string()` — only file-based input via `open()`. Malformed log lines produce a row with the `_error` field set instead of throwing an exception.
</Note>

***

### `Dir`

**Class:** `FQL\Stream\Dir`\
**Formats:** `dir`

```php theme={null}
public static function open(string $path): Interface\Stream
```

Treats a directory as a data source. Each file in the directory becomes a row.

```php theme={null}
use FQL\Stream\Dir;

$query = Dir::open('/var/log/')->query();
```

***

## `query()` method

All stream classes inherit `query()` from `AbstractStream`.

```php theme={null}
public function query(): FQL\Query\Query
```

Returns a fresh `Query` bound to this stream. See the [Query\Provider reference](/api/query-provider) for the full fluent API.

```php theme={null}
use FQL\Stream\Json;
use FQL\Enum\Operator;

$results = Json::open('products.json')
    ->query()
    ->select('id', 'name', 'price')
    ->from('products')
    ->where('price', Operator::LESS_THAN, 50)
    ->limit(20)
    ->execute();
```
