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

feat: flat renderer #3

Merged
merged 1 commit into from Oct 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 20 additions & 6 deletions doc/RenderAsString.md
Expand Up @@ -19,16 +19,30 @@ Note that the leading question mark will never be included.

## Change renderer

Remove numeric indices:
### Remove numeric indices:
This renderer will render indexed arrays as `foo[]=bar&foo[]=baz` instead of `foo[0]=bar&foo[1]=baz`.

```php
use function BenTools\QueryString\withoutNumericIndices;
$qs = $qs->withRenderer(
withoutNumericIndices()
);
print(urldecode((string) $qs)); // yummy[fruits][]=strawberries&yummy[fruits][]=raspberries

$qs = $qs->withRenderer(withoutNumericIndices());
print(urldecode((string) $qs));
```

Or define it on a global scope for future QueryString objects:
### Flat renderer
This renderer will render indexed arrays as `foo=bar&foo=baz` instead of `foo[0]=bar&foo[1]=baz`.

```php
use function BenTools\QueryString\flat;

$qs = $qs->withRenderer(flat());
print(urldecode((string) $qs));
```

### Global setting

You can define a default renderer on a global scope for future QueryString objects:

```php
use BenTools\QueryString\QueryString;
use function BenTools\QueryString\withoutNumericIndices;
Expand Down
86 changes: 86 additions & 0 deletions src/Renderer/FlatRenderer.php
@@ -0,0 +1,86 @@
<?php

namespace BenTools\QueryString\Renderer;

use BenTools\QueryString\QueryString;

final class FlatRenderer implements QueryStringRendererInterface
{
/**
* @var NativeRenderer
*/
private $renderer;

protected function __construct(QueryStringRendererInterface $renderer = null)
{
$this->renderer = $renderer;
}

public static function factory(QueryStringRendererInterface $renderer = null)
{
return new self($renderer ?? NativeRenderer::factory());
}

/**
* @inheritDoc
*/
public function render(QueryString $queryString): string
{
$separator = $this->getSeparator() ?? ini_get('arg_separator.output');
$parts = [[]];

foreach ($queryString->getParams() as $key => $value) {
$parts[] = $this->getParts($key, $value);
}

return \implode($separator, \array_merge([], ...$parts));
}

/**
* @inheritDoc
*/
public function getEncoding(): int
{
return $this->renderer->getEncoding();
}

/**
* @inheritDoc
*/
public function withEncoding(int $encoding): QueryStringRendererInterface
{
return new self($this->renderer->withEncoding($encoding));
}

/**
* @inheritDoc
*/
public function getSeparator(): ?string
{
return $this->renderer->getSeparator();
}

/**
* @inheritDoc
*/
public function withSeparator(?string $separator): QueryStringRendererInterface
{
return new self($this->renderer->withSeparator($separator));
}

private function getParts($key, $value): array
{
if (\is_iterable($value)) {
$parts = [[]];
foreach ($value as $sub) {
$parts[] = $this->getParts($key, $sub);
}

return \array_merge([], ...$parts);
}

$encode = \PHP_QUERY_RFC1738 === $this->getEncoding() ? '\\urlencode' : '\\rawurlencode';

return [$key . '=' . \call_user_func($encode, $value)];
}
}
10 changes: 10 additions & 0 deletions src/functions.php
Expand Up @@ -4,6 +4,7 @@

use BenTools\QueryString\Parser\QueryStringParserInterface;
use BenTools\QueryString\Renderer\ArrayValuesNormalizerRenderer;
use BenTools\QueryString\Renderer\FlatRenderer;
use BenTools\QueryString\Renderer\QueryStringRendererInterface;

/**
Expand All @@ -25,6 +26,15 @@ function withoutNumericIndices(QueryStringRendererInterface $renderer = null): A
return ArrayValuesNormalizerRenderer::factory($renderer);
}

/**
* @param QueryStringRendererInterface|null $renderer
* @return FlatRenderer
*/
function flat(QueryStringRendererInterface $renderer = null): FlatRenderer
{
return FlatRenderer::factory($renderer);
}

/**
* @param string $queryString
* @param bool $decodeKeys
Expand Down
41 changes: 41 additions & 0 deletions tests/FlatRendererTest.php
@@ -0,0 +1,41 @@
<?php

namespace BenTools\QueryString\Tests;

use PHPUnit\Framework\TestCase;
use function BenTools\QueryString\flat;
use function BenTools\QueryString\query_string;

class FlatRendererTest extends TestCase
{
public function testRenderer()
{
$data = [
'foo' => 'bar',
'foos' => [
'bar',
'foo bar',
],
'fruits' => [
'banana' => 'yellow',
'strawberry' => 'red',
],
];

$qs = query_string($data);
$renderer = flat();

$this->assertEquals('foo=bar&foos=bar&foos=foo%20bar&fruits=yellow&fruits=red', (string) $qs->withRenderer(
$renderer
));

$this->assertEquals('foo=bar&foos=bar&foos=foo+bar&fruits=yellow&fruits=red', (string) $qs->withRenderer(
$renderer->withEncoding(PHP_QUERY_RFC1738)
));

$this->assertEquals('foo=bar;foos=bar;foos=foo+bar;fruits=yellow;fruits=red', (string) $qs->withRenderer(
$renderer->withEncoding(PHP_QUERY_RFC1738)->withSeparator(';')
));
}

}