Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to format duplicate keys #3

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
strategy:
fail-fast: true
matrix:
php: [7.0, 7.1, 7.2, 7.3, 7.4, 8.0, 8.1, 8.2]
php: [7.0, 7.1, 7.2, 7.3, 7.4, 8.0, 8.1, 8.2, 8.3]

name: PHP ${{ matrix.php }}

Expand Down
37 changes: 32 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
# VDF Converter

![Tests](https://github.com/exayer/vdf-converter/workflows/Tests/badge.svg)
[![Total Downloads](https://img.shields.io/packagist/dt/EXayer/vdf-converter)](https://packagist.org/packages/exayer/vdf-converter)
![Latest Stable Version](https://img.shields.io/packagist/v/exayer/vdf-converter)

A memory efficient parser for the Valve Data Format (*.vdf) written in PHP.
Expand Down Expand Up @@ -89,8 +88,7 @@ $result = iterator_to_array($planets);

Some VDFs are known to contain duplicate keys.
To keep the result structure the same as the VDF and since the parser is generator based (not keeping in memory pairs)
the duplicated key will be modified - the counter will be concatenated to the end (e.g. 'key__2').

the duplicated key will be modified - the counter will be concatenated to the end (e.g. `key__[2]`).

```php
$vdf = '{
Expand All @@ -114,16 +112,45 @@ $result = iterator_to_array(VdfConverter::fromString($vdf));
// "mercury" => [
// "distance" => "58"
// "velocity" => "35"
// "distance__2" => "92"
// "distance__[2]" => "92"
// ]
// "mercury__2" => [
// "mercury__[2]" => [
// "distance" => "108"
// ]
// "earth" => [
// "distance" => "149"
// ]
// ]
```

#### Customizing key format

If you want to customize the formatting key process, you can create your own custom formatter. A formatter is any class that implements `EXayer\VdfConverter\UniqueKey\Formatter`.

This is what that interface looks like.

```php
namespace EXayer\VdfConverter\UniqueKey;

interface Formatter
{
public function buildKeyName(string $key, int $index): string;
}
```

After creating your formatter, you can specify its class name in the `uniqueKeyFormatter` method of the `EXayer\VdfConverter\VdfConverterConfig` object. The config can be passed as second argument to any `from` builder method. Your formatter will then be used by default for all duplicate key handling calls.

You can also specify a signer for a specific webhook call:

```php
$config = VdfConverterConfig::create()
->uniqueKeyFormatter(YourCustomFormatter::class);

$iterator = VdfConverter::fromString($vdf, $config);
```

**Warning**: Do not create formatters that create a key like `__2`, as some VDFs may have keys in this format.

## Testing

```bash
Expand Down
Binary file modified logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 6 additions & 4 deletions src/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace EXayer\VdfConverter;

use EXayer\VdfConverter\Exception\CouldNotParseException;
use EXayer\VdfConverter\UniqueKey\UniqueKeyHandler;
use Traversable;

class Parser implements \IteratorAggregate, PositionAwareInterface, LineColumnAwareInterface
Expand All @@ -13,17 +14,18 @@ class Parser implements \IteratorAggregate, PositionAwareInterface, LineColumnAw
private $lexer;

/**
* @var UniqueKey
* @var UniqueKeyHandler
*/
private $uniqueKey;

/**
* @param Traversable $lexer
* @param Traversable $lexer
* @param VdfConverterConfig $config
*/
public function __construct(Traversable $lexer)
public function __construct(Traversable $lexer, VdfConverterConfig $config)
{
$this->lexer = $lexer;
$this->uniqueKey = new UniqueKey();
$this->uniqueKey = new UniqueKeyHandler($config->getUniqueKeyFormatter());
}

/**
Expand Down
14 changes: 14 additions & 0 deletions src/UniqueKey/DefaultFormatter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace EXayer\VdfConverter\UniqueKey;

class DefaultFormatter implements Formatter
{
/**
* {@inheritDoc}
*/
public function buildKeyName(string $key, int $index): string
{
return $key . '__[' . $index . ']';
}
}
16 changes: 16 additions & 0 deletions src/UniqueKey/Formatter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace EXayer\VdfConverter\UniqueKey;

interface Formatter
{
/**
* Returns a formatted key based on original key and duplicate index.
*
* @param string $key Original key.
* @param int $index Duplicate key index.
*
* @return string
*/
public function buildKeyName(string $key, int $index): string;
}
28 changes: 13 additions & 15 deletions src/UniqueKey.php → src/UniqueKey/UniqueKeyHandler.php
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<?php

namespace EXayer\VdfConverter;
namespace EXayer\VdfConverter\UniqueKey;

class UniqueKey
class UniqueKeyHandler
{
/**
* @const
* @var Formatter
*/
const DELIMITER = '__';
private $formatter;

/**
* Holds duplicate key counts for each level of nesting.
Expand All @@ -17,6 +17,14 @@ class UniqueKey
*/
private $storage = [];

/**
* @param Formatter $formatter
*/
public function __construct(Formatter $formatter)
{
$this->formatter = $formatter;
}

/**
* @param int $level Buffer nesting level.
* @param string $key
Expand All @@ -30,7 +38,7 @@ public function get(int $level, string $key): string
return $key;
}

return $this->buildName($key, ++$this->storage[$level][$key]);
return $this->formatter->buildKeyName($key, ++$this->storage[$level][$key]);
}

/**
Expand All @@ -42,14 +50,4 @@ public function clear(int $level)
$this->storage[$level] = [];
}
}

/**
* @param string $key
* @param int $index
* @return string
*/
private function buildName(string $key, int $index): string
{
return $key . self::DELIMITER . $index;
}
}
37 changes: 22 additions & 15 deletions src/VdfConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,52 +19,59 @@ class VdfConverter implements \IteratorAggregate, PositionAwareInterface
private $parser;

/**
* @param iterable $bytesIterator
* @param iterable $bytesIterator
* @param VdfConverterConfig|null $config
*/
public function __construct($bytesIterator)
public function __construct($bytesIterator, VdfConverterConfig $config = null)
{
$this->bytesIterator = $bytesIterator;
$this->parser = new Parser(new Lexer($this->bytesIterator));

$config = $config ?: new VdfConverterConfig();
$this->parser = new Parser(new Lexer($this->bytesIterator), $config);
}

/**
* @param string $string
* @param string $string
* @param VdfConverterConfig|null $config
*
* @return self
*/
public static function fromString(string $string): self
public static function fromString(string $string, VdfConverterConfig $config = null): self
{
return new static(new StringChunks($string));
return new static(new StringChunks($string), $config);
}

/**
* @param string $fileName
* @param string $fileName
* @param VdfConverterConfig|null $config
*
* @return self
*/
public static function fromFile(string $fileName): self
public static function fromFile(string $fileName, VdfConverterConfig $config = null): self
{
return new static(new FileChunks($fileName));
return new static(new FileChunks($fileName), $config);
}

/**
* @param resource $stream
* @param resource $stream
* @param VdfConverterConfig|null $config
*
* @return self
*/
public static function fromStream($stream): self
public static function fromStream($stream, VdfConverterConfig $config = null): self
{
return new static(new StreamChunks($stream));
return new static(new StreamChunks($stream), $config);
}

/**
* @param \Traversable|array $iterable
* @param \Traversable|array $iterable
* @param VdfConverterConfig|null $config
*
* @return self
*/
public static function fromIterable($iterable): self
public static function fromIterable($iterable, VdfConverterConfig $config = null): self
{
return new static($iterable);
return new static($iterable, $config);
}

/**
Expand Down
42 changes: 42 additions & 0 deletions src/VdfConverterConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace EXayer\VdfConverter;

use EXayer\VdfConverter\UniqueKey\DefaultFormatter;
use EXayer\VdfConverter\UniqueKey\Formatter;

class VdfConverterConfig
{
/**
* @var string
*/
private $uniqueKeyFormatter = DefaultFormatter::class;

/**
* @return self
*/
public static function create(): self
{
return new self();
}

/**
* @param string $formatterClassName
*
* @return $this
*/
public function uniqueKeyFormatter(string $formatterClassName): self
{
$this->uniqueKeyFormatter = $formatterClassName;

return $this;
}

/**
* @return Formatter
*/
public function getUniqueKeyFormatter(): Formatter
{
return new $this->uniqueKeyFormatter;
}
}
Loading
Loading