Compare commits

..

1 commit
main ... v1.4

Author SHA1 Message Date
31db2e67c5 porting tests and a bug fix from v1.5 2022-12-06 11:25:59 -07:00
14 changed files with 172 additions and 243 deletions

View file

@ -1,14 +0,0 @@
name: phpstan
on: push
jobs:
phpstan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: php-actions/composer@v6
with:
dev: yes
- uses: php-actions/phpstan@v3
with:
memory_limit: 1G
args: --memory-limit 1G

View file

@ -1,11 +0,0 @@
name: phpunit
on: push
jobs:
phpunit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: php-actions/composer@v6
with:
dev: yes
- uses: php-actions/phpunit@v3

View file

@ -1,7 +1,6 @@
# Flatrr
[![phpstan](https://github.com/jobyone/flatrr/actions/workflows/phpstan.yml/badge.svg?branch=v1.5)](https://github.com/jobyone/flatrr/actions/workflows/phpstan.yml)
[![phpunit](https://github.com/jobyone/flatrr/actions/workflows/phpunit.yml/badge.svg?branch=v1.5)](https://github.com/jobyone/flatrr/actions/workflows/phpunit.yml)
[![Build Status](https://travis-ci.org/jobyone/flatrr.svg?branch=main)](https://travis-ci.org/jobyone/flatrr)
[![Latest Stable Version](http://poser.pugx.org/byjoby/flatrr/v)](https://packagist.org/packages/byjoby/flatrr)
[![Total Downloads](http://poser.pugx.org/byjoby/flatrr/downloads)](https://packagist.org/packages/byjoby/flatrr)
[![Latest Unstable Version](http://poser.pugx.org/byjoby/flatrr/v/unstable)](https://packagist.org/packages/byjoby/flatrr)

View file

@ -3,16 +3,12 @@
"description": "A library for working with multi-dimensional arrays through flattened keys",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Joby Elliott",
"email": "joby@byjoby.com"
}
],
"authors": [{
"name": "Joby Elliott",
"email": "joby@byjoby.com"
}],
"require-dev": {
"phpunit/phpunit": "^9.5",
"phpstan/phpstan": "^1.9",
"squizlabs/php_codesniffer": "^3.7"
"phpunit/phpunit": "^9.5"
},
"autoload": {
"psr-4": {
@ -25,12 +21,12 @@
}
},
"scripts": {
"test": "phpunit",
"stan": "phpstan",
"sniff": "phpcs"
"test": [
"phpunit"
]
},
"require": {
"php": ">=8.1",
"symfony/yaml": "^6.4"
"php": ">=7.1",
"mustangostang/spyc": "^0.6.3"
}
}
}

View file

@ -1,19 +0,0 @@
<?xml version="1.0"?>
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="PHP_CodeSniffer"
xsi:noNamespaceSchemaLocation="./vendor/squizlabs/php_codesniffer/phpcs.xsd">
<description>Coding Standard</description>
<file>src</file>
<arg name="basepath" value="." />
<arg name="colors" />
<arg name="parallel" value="75" />
<arg value="np" />
<rule ref="PSR12">
<exclude name="Generic.Files.LineEndings" />
<exclude name="Generic.NamingConventions.CamelCapsFunctionName" />
<exclude name="PSR1.Methods.CamelCapsMethodName" />
</rule>
</ruleset>

View file

@ -1,4 +0,0 @@
parameters:
level: 7
paths:
- src

View file

@ -1,31 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
executionOrder="random"
failOnWarning="true"
failOnRisky="true"
failOnEmptyTestSuite="true"
beStrictAboutOutputDuringTests="true"
verbose="true"
bootstrap="vendor/autoload.php">
<php>
<ini name="display_errors" value="On" />
<ini name="error_reporting" value="-1" />
<ini name="xdebug.mode" value="coverage" />
</php>
<phpunit bootstrap="vendor/autoload.php">
<testsuites>
<testsuite name="Tests">
<directory>tests/</directory>
<testsuite name="All">
<directory>tests</directory>
</testsuite>
</testsuites>
<coverage>
<include>
<directory suffix=".php">src</directory>
</include>
<report>
<html outputDirectory="coverage" lowUpperBound="50" highLowerBound="90" />
</report>
</coverage>
</phpunit>
</phpunit>

View file

@ -1,81 +1,105 @@
<?php
/* Flatrr | https://github.com/jobyone/flatrr | MIT License */
/* Flatrr | https://gitlab.com/byjoby/flatrr | MIT License */
namespace Flatrr\Config;
use Flatrr\SelfReferencingFlatArray;
use Symfony\Component\Yaml\Yaml;
use Spyc;
class Config extends SelfReferencingFlatArray implements ConfigInterface
{
public function readDir(string $dir, string $name = null, bool $overwrite = false): static
public $strict = false;
public function readDir($dir, string $name = null, bool $overwrite = false)
{
$dir = realpath($dir);
if ($dir && is_dir($dir)) {
$glob = glob("$dir/*");
if ($glob) {
foreach ($glob as $f) {
if (is_file($f)) {
$this->readFile($f, $name, $overwrite);
}
}
if (!$dir || !is_dir($dir)) {
return;
}
foreach (glob("$dir/*") as $f) {
if (is_file($f)) {
$this->readFile($f, $name, $overwrite);
}
}
return $this;
}
public function json(bool $raw = false): string
protected function parse(string $input, string $format): array
{
return json_encode($this->get(null, $raw), JSON_PRETTY_PRINT); // @phpstan-ignore-line
$fn = 'parse_' . $format;
if (!method_exists($this, $fn)) {
if ($this->strict) {
throw new \Exception("Don't know how to parse the format \"$format\"");
} else {
return null;
}
}
if ($out = $this->$fn($input)) {
return $out;
}
return array();
}
public function yaml(bool $raw = false): string
protected function parse_yaml($input)
{
return Yaml::dump(
$this->get(null, $raw),
2,
2,
Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK
);
return Spyc::YAMLLoadString($input);
}
/** @return array<mixed|mixed> */
protected function read_ini(string $filename): false|array
public function json($raw = false): string
{
return json_encode($this->get(null, $raw), JSON_PRETTY_PRINT);
}
public function yaml($raw = false): string
{
return Spyc::YAMLDump($this->get(null, $raw), 2);
}
protected function read_ini($filename)
{
return parse_ini_file($filename, true);
}
/** @return array<mixed|mixed> */
protected function read_json(string $filename): null|array
protected function read_json($filename)
{
/** @var string */
$data = file_get_contents($filename);
return json_decode($data, true);
return json_decode(file_get_contents($filename), true);
}
/** @return array<mixed|mixed> */
protected function read_yaml(string $filename): array
protected function read_yaml($filename)
{
return Yaml::parseFile($filename);
return Spyc::YAMLLoad($filename);
}
/** @return array<mixed|mixed> */
protected function read_yml(string $filename): array
protected function read_yml($filename)
{
return $this->read_yaml($filename);
}
public function readFile(string $filename, string $name = null, bool $overwrite = false): static
public function readFile($filename, string $name = null, bool $overwrite = false)
{
$format = strtolower(preg_replace('/.+\./', '', $filename));
$fn = 'read_' . $format;
if (is_file($filename) && is_readable($filename) && method_exists($this, $fn)) {
$data = $this->$fn($filename);
if ($data !== null) {
$this->merge($data, $name, $overwrite);
if (!is_file($filename) || !is_readable($filename)) {
if ($this->strict) {
throw new \Exception("Couldn't read config file \"$filename\"");
} else {
return null;
}
}
return $this;
$format = strtolower(preg_replace('/.+\./', '', $filename));
$fn = 'read_' . $format;
if (!method_exists($this, $fn)) {
if ($this->strict) {
throw new \Exception("Don't know how to read the format \"$format\"");
} else {
return null;
}
}
$data = $this->$fn($filename);
if (!$data) {
if ($this->strict) {
throw new \Exception("Error reading \"" . $filename . "\"");
} else {
return null;
}
}
$this->merge($data, $name, $overwrite);
}
}

View file

@ -1,17 +1,12 @@
<?php
/* Flatrr | https://github.com/jobyone/flatrr | MIT License */
/* Flatrr | https://gitlab.com/byjoby/flatrr | MIT License */
namespace Flatrr\Config;
use Flatrr\FlatArrayInterface;
interface ConfigInterface extends FlatArrayInterface
interface ConfigInterface extends \ArrayAccess
{
public function readDir(string $dir, string $name = null, bool $overwrite = false): static;
public function readFile(string $filename, string $name = null, bool $overwrite = false): static;
public function json(bool $raw = false): string;
public function yaml(bool $raw = false): string;
public function get(null|string $name = null, bool $raw = false): mixed;
public function merge(mixed $value, string $name = null, bool $overwrite = false): static;
public function readFile($filename, string $name = null, bool $overwrite = false);
public function json($raw = false) : string;
public function yaml($raw = false) : string;
public function get(string $name = null, bool $raw = false);
public function merge($value, string $name = null, bool $overwrite = false);
}

View file

@ -1,18 +1,12 @@
<?php
/* Flatrr | https://github.com/jobyone/flatrr | MIT License */
/* Flatrr | https://gitlab.com/byjoby/flatrr | MIT License */
namespace Flatrr;
class FlatArray implements FlatArrayInterface
{
use FlatArrayTrait;
/**
* @param null|array<string|mixed> $data
* @return void
*/
public function __construct(null|array $data = null)
public function __construct(array $data = null)
{
$this->merge($data);
}

View file

@ -1,25 +1,16 @@
<?php
/* Flatrr | https://github.com/jobyone/flatrr | MIT License */
/* Flatrr | https://gitlab.com/byjoby/flatrr | MIT License */
namespace Flatrr;
use ArrayAccess;
use Iterator;
/**
* @extends ArrayAccess<string,mixed>
* @extends Iterator<string,mixed>
*/
interface FlatArrayInterface extends ArrayAccess, Iterator
interface FlatArrayInterface extends \ArrayAccess, \Iterator
{
public function set(null|string $name, mixed $value): mixed;
public function get(null|string $name = null): mixed;
public function unset(null|string $name): static;
public function merge(mixed $value, string $name = null, bool $overwrite = false): static;
public function set(?string $name, $value);
public function get(?string $name = null);
public function unset(?string $name);
public function merge($value, string $name = null, bool $overwrite = false);
public function push(null|string $name, mixed $value): static;
public function pop(null|string $name): mixed;
public function unshift(null|string $name, mixed $value): static;
public function shift(null|string $name): mixed;
public function push(?string $name, $value);
public function pop(?string $name);
public function unshift(?string $name, $value);
public function shift(?string $name);
}

View file

@ -1,35 +1,31 @@
<?php
/* Flatrr | https://github.com/jobyone/flatrr | MIT License */
/* Flatrr | https://gitlab.com/byjoby/flatrr | MIT License */
namespace Flatrr;
trait FlatArrayTrait
{
/** @var array<string|mixed> */
protected $_arrayData = [];
/** @var array<string|mixed> */
protected $_flattenCache = [];
private $_arrayData = array();
private $_flattenCache = array();
public function push(null|string $name, mixed $value): static
public function push(?string $name, $value)
{
$arr = $this->flattenSearch($name);
if ($arr !== null && !is_array($arr)) {
return $this;
return;
}
if ($arr === null) {
$arr = [];
}
$arr[] = $value;
$this->set($name, $arr);
return $this;
}
public function pop(null|string $name): mixed
public function pop(?string $name)
{
$arr = $this->flattenSearch($name);
if ($arr !== null && !is_array($arr)) {
return null;
return;
}
$out = array_pop($arr);
$this->unset($name);
@ -37,25 +33,24 @@ trait FlatArrayTrait
return $out;
}
public function unshift(null|string $name, mixed $value): static
public function unshift(?string $name, $value)
{
$arr = $this->flattenSearch($name);
if ($arr !== null && !is_array($arr)) {
return $this;
return;
}
if ($arr === null) {
$arr = [];
}
array_unshift($arr, $value);
$this->set($name, $arr);
return $this;
}
public function shift(null|string $name): mixed
public function shift(?string $name)
{
$arr = $this->flattenSearch($name);
if ($arr !== null && !is_array($arr)) {
return null;
return;
}
$out = array_shift($arr);
$this->unset($name);
@ -63,64 +58,62 @@ trait FlatArrayTrait
return $out;
}
public function set(null|string $name, mixed $value): static
public function set(?string $name, $value)
{
$this->flattenSearch($name, $value);
return $this;
return $this->flattenSearch($name, $value);
}
public function get(null|string $name = null): mixed
public function get(?string $name = null)
{
return $this->flattenSearch($name);
}
public function unset(null|string $name): static
function unset(?string $name)
{
$this->flattenSearch($name, null, true);
return $this;
}
public function offsetSet($name, $value): void
public function offsetSet($name, $value)
{
$this->set($name, $value);
return $this->set($name, $value);
}
public function offsetGet($name): mixed
public function offsetGet($name)
{
return $this->get($name);
}
public function offsetExists($name): bool
public function offsetExists($name)
{
return $this->flattenSearch($name) !== null;
}
public function offsetUnset($name): void
public function offsetUnset($name)
{
$this->unset($name);
}
public function rewind(): void
public function rewind()
{
reset($this->_arrayData);
return reset($this->_arrayData);
}
public function current(): mixed
public function current()
{
return current($this->_arrayData);
}
public function next(): void
public function next()
{
next($this->_arrayData);
return next($this->_arrayData);
}
public function key(): null|string|int
public function key()
{
return key($this->_arrayData);
}
public function valid(): bool
public function valid()
{
return isset($this->_arrayData[$this->key()]);
}
@ -129,11 +122,12 @@ trait FlatArrayTrait
* Recursively set a value, with control over whether existing values or new
* values take precedence
*/
public function merge(mixed $value, string $name = null, bool $overwrite = false): static
public function merge($value, string $name = null, bool $overwrite = false)
{
if (!isset($this[$name])) {
//easiest possible outcome, old value doesn't exist, so we can just write the value
$this->set($name, $value);
return;
} elseif (is_array($value) && is_array($this->flattenSearch($name))) {
//both new and old values are arrays
foreach ($value as $k => $v) {
@ -142,13 +136,14 @@ trait FlatArrayTrait
}
$this->merge($v, $k, $overwrite);
}
return;
} else {
//old and new values exist, and one or both are not arrays, $overwrite rules the day
if ($overwrite) {
$this->set($name, $value);
}
return;
}
return $this;
}
/**
@ -156,10 +151,10 @@ trait FlatArrayTrait
* string. It sets it if $value exists, otherwise it returns the value if it
* exists.
*/
protected function flattenSearch(null|string $name, mixed $value = null, bool $unset = false): mixed
protected function flattenSearch(?string $name, $value = null, $unset = false)
{
if ($value !== null || $unset) {
$this->_flattenCache = [];
$this->_flattenCache = array();
}
if (!isset($this->_flattenCache[$name])) {
$this->_flattenCache[$name] = $this->doFlattenSearch($name, $value, $unset);
@ -167,7 +162,7 @@ trait FlatArrayTrait
return $this->_flattenCache[$name];
}
protected function doFlattenSearch(null|string $name, mixed $value = null, bool $unset = false): mixed
protected function doFlattenSearch(?string $name, $value = null, $unset = false)
{
//check for home strings
if ($name == '' || $name === null) {
@ -185,7 +180,7 @@ trait FlatArrayTrait
if ($value !== null) {
foreach ($name as $part) {
if (!isset($parent[$part])) {
$parent[$part] = [];
$parent[$part] = array();
}
$parent = &$parent[$part];
}
@ -206,9 +201,9 @@ trait FlatArrayTrait
//both value and destination are arrays, merge them
$parent[$key] = array_replace_recursive($parent[$key], $value);
} else {
//destination is not an array, to set this we must overwrite it with an empty array
if (!is_array(@$parent[$key])) {
$parent[$key] = [];
//set the hard way
if (!is_array($parent)) {
$parent = array();
}
$parent[$key] = $value;
}

View file

@ -1,15 +1,13 @@
<?php
/* Flatrr | https://github.com/jobyone/flatrr | MIT License */
/* Flatrr | https://gitlab.com/byjoby/flatrr | MIT License */
namespace Flatrr;
class SelfReferencingFlatArray extends FlatArray
{
/** @var array<string,string> */
protected $cache = [];
public function get(string $name = null, bool $raw = false, bool $unescape = true): mixed
public function get(string $name = null, bool $raw = false, $unescape = true)
{
$out = parent::get($name);
if ($raw) {
@ -22,29 +20,48 @@ class SelfReferencingFlatArray extends FlatArray
return $out;
}
public function set(null|string $name, mixed $value): static
public function set(?string $name, $value)
{
$this->cache = [];
$this->filter(parent::set($name, $value));
return $this;
return $this->filter(parent::set($name, $value));
}
public function pop(null|string $name): mixed
public function push(?string $name, $value)
{
return $this->filter(parent::push($name, $value));
}
public function pop(?string $name)
{
return $this->filter(parent::pop($name));
}
public function shift(null|string $name): mixed
public function unshift(?string $name, $value)
{
return $this->filter(parent::unshift($name, $value));
}
public function shift(?string $name)
{
return $this->filter(parent::shift($name));
}
public function current(): mixed
public function rewind()
{
return $this->filter(parent::rewind());
}
public function next()
{
return $this->filter(parent::next());
}
public function current()
{
return $this->filter(parent::current());
}
protected function unescape(mixed $value): mixed
protected function unescape($value)
{
//map this function onto array values
if (is_array($value)) {
@ -71,7 +88,7 @@ class SelfReferencingFlatArray extends FlatArray
/**
* Recursively replace ${var/name} type strings in string values with
*/
protected function filter(mixed $value): mixed
protected function filter($value)
{
//map this function onto array values
if (is_array($value)) {
@ -97,14 +114,9 @@ class SelfReferencingFlatArray extends FlatArray
return $value;
}
/**
* @param array<int,null|string> $matches
* @return string
*/
protected function filter_regex(array $matches): string
protected function filter_regex($matches)
{
$value = $this->get($matches[1], false, false);
if ($value !== null) {
if (null !== $value = $this->get($matches[1], false, false)) {
if (!is_array($value)) {
return $value;
}

View file

@ -6,7 +6,7 @@ declare(strict_types=1);
namespace Flatrr\Config;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Yaml\Yaml;
use Spyc;
class ConfigTest extends TestCase
{
@ -38,11 +38,6 @@ class ConfigTest extends TestCase
$a = new Config();
$a->readFile(__DIR__ . '/configtest.yaml');
$this->assertEquals($data, $a->get());
//nonexistant files
$a = new Config();
$a->readFile(__DIR__ . '/does-not-exist.json');
$a->readFile(__DIR__ . '/does-not-exist.yaml');
$this->assertEquals([], $a->get());
}
public function testSerializing()
@ -57,7 +52,7 @@ class ConfigTest extends TestCase
//json
$this->assertEquals($data, json_decode($c->json(), true));
//yaml
$this->assertEquals($data, Yaml::parse($c->yaml()));
$this->assertEquals($data, Spyc::YAMLLoad($c->yaml()));
}
public function testReadingDirectory()