Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,8 @@ insert_final_newline = true
indent_style = tab
indent_size = 4

[*.yml]
indent_size = 2

[*.md]
indent_style = space
39 changes: 39 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Unit Tests

on:
push:
pull_request:

jobs:
tests:
name: Unit Tests
runs-on: ubuntu-24.04
strategy:
matrix:
include:
- php: '8.0'
- php: '8.1'
- php: '8.2'
- php: '8.3'
- php: '8.4'
steps:
- uses: actions/checkout@v4

- name: Cache Composer dependencies
uses: actions/cache@v3
with:
path: ./vendor
key: composer-${{ runner.os }}-${{ hashFiles('**/composer.json') }}

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
coverage: "none"
php-version: "${{ matrix.php }}"

- name: Install dependencies
run: composer install

- name: Test
run: |
composer test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.idea
/vendor/
composer.lock
.phpunit.result.cache
10 changes: 0 additions & 10 deletions .travis.yml

This file was deleted.

4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,7 @@ Find the first item that passes the given truth test.
```php
$dot->first('groups.*.items.*.rare', true)->get(); // ['name' => 'item3', 'rare' => true]

$dot->first('groups.*.items.*', function (array $item) {
return $item['rare'] === true;
})->get(); // same as above
$dot->first('groups.*.items.*', fn (array $item) => $item['rare'] === true)->get(); // same as above
```

#### `Dot::get(null|int|string $path): mixed`
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
"test": "phpunit"
},
"require": {
"php": "^7.0|^8.0"
"php": "^8.0"
},
"require-dev": {
"phpunit/phpunit": "^6.5|^7.5"
"phpunit/phpunit": "^9.6|^10.5|^11.5|^12.4"
},
"autoload": {
"psr-4": {
Expand Down
18 changes: 11 additions & 7 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/autoload.php">
<phpunit
beStrictAboutTestsThatDoNotTestAnything="true"
beStrictAboutOutputDuringTests="true"
bootstrap="vendor/autoload.php"
colors="true"
>
<testsuites>
<testsuite name="noj/dot tests">
<testsuite name="Dot tests">
<directory suffix="Test.php">./test</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<source>
<include>
<directory suffix=".php">./src</directory>
</whitelist>
</filter>
</include>
</source>
</phpunit>
42 changes: 19 additions & 23 deletions src/Dot.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,11 @@

class Dot
{
private $data;

public function __construct(&$data)
public function __construct(private mixed &$data)
{
$this->data = &$data;
}

public static function from(&$data): self
public static function from(array|object &$data): self
{
return new self($data);
}
Expand All @@ -27,7 +24,7 @@ public function count(string $path = null): int
return is_array($values) ? \count(array_filter($values)) : 0;
}

public function find(string $path, $equals): self
public function find(string $path, mixed $equals): self
{
$parser = new Parser();
$nodeList = $parser->parse($this->data, $path);
Expand Down Expand Up @@ -67,26 +64,27 @@ public function first(string $path = null, $equals = null): self
return $this->find($path, $equals)->first();
}

/**
* @param null|int|string $path
*
* @return array|mixed|null
*/
public function get($path = null)
public function get(int|string|null $path = null)
{
if ($path === null) {
return $this->data;
}

return $this->select($path)->data;
$selected = $this->select($path);

if ($selected instanceof self) {
return $selected->data;
}

return $selected;
}

public function has(string $path): bool
public function has(int|string $path): bool
{
return $this->get($path) !== null;
}

public function push(string $path, $value): self
public function push(string $path, mixed $value): self
{
$parser = new Parser();
$nodeList = $parser->parse($this->data, $path);
Expand All @@ -99,7 +97,7 @@ public function push(string $path, $value): self
return $this;
}

public function set($paths, $value = null)
public function set(array|string $paths, mixed $value = null)
{
if (is_array($paths)) {
foreach ($paths as $path => $pathValue) {
Expand Down Expand Up @@ -137,9 +135,9 @@ public function set($paths, $value = null)
}
}

private function select($path): self
private function select(int|string $path): mixed
{
if (is_int($path)) {
if (is_numeric($path)) {
$value = $this->data[$path] ?? null;
return new self($value);
}
Expand Down Expand Up @@ -168,11 +166,9 @@ private function select($path): self
return new self($flattened);
}

private function equality($value): callable
private function equality(mixed $value): callable
{
return function ($item) use ($value) {
return $item === $value;
};
return static fn($item) => $item === $value;
}

private function flatten(array &$values): array
Expand All @@ -188,7 +184,7 @@ private function flatten(array &$values): array
return $flattened;
}

private function &wrap(&$value): array
private function &wrap(mixed &$value): array
{
if (is_array($value)) {
return $value;
Expand Down
2 changes: 1 addition & 1 deletion src/Exception/InvalidMethodException.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class InvalidMethodException extends DotException
{
public static function fromNode(Node $node): self
{
$type = is_object($node->item) ? get_class($node->item) : gettype($node->item);
$type = get_debug_type($node->item);
return new self("Can't call method {$node->getMethodName()} on $type");
}
}
16 changes: 5 additions & 11 deletions src/Parser/Node.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,8 @@

class Node
{
public $item;
public $segment;

public function __construct(&$item, Segment $segment)
public function __construct(public array|object &$item, public Segment $segment)
{
$this->item = &$item;
$this->segment = $segment;
}

public function withSegment(Segment $segment): Node
Expand All @@ -22,12 +17,11 @@ public function withSegment(Segment $segment): Node

/**
* @throws InvalidMethodException
* @return mixed|null
*/
public function &accessValue($initialiseIfNotSet = false)
public function &accessValue($initialiseIfNotSet = false): mixed
{
if ($method = $this->getMethod()) {
$result = $method ? $method->invoke($this->item) : null;
$result = $method?->invoke($this->item);
return $result;
}

Expand All @@ -52,7 +46,7 @@ public function &accessValue($initialiseIfNotSet = false)
return $this->item->{$this->segment->key};
}

public function getMethod()
public function getMethod(): ?\ReflectionMethod
{
if (!$this->isMethodCall()) {
return null;
Expand All @@ -72,7 +66,7 @@ public function isMethodCall(): bool
return strpos($this->segment->key, '@') === 0;
}

public function getMethodName()
public function getMethodName(): string
{
return substr($this->segment->key, 1);
}
Expand Down
16 changes: 6 additions & 10 deletions src/Parser/NodeList.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,9 @@
class NodeList
{
/** @var (self|Node)[] */
public $items = [];
public array $items = [];

/**
* @param self|Node $item
*
* @return self
*/
public function add($item): self
public function add(Node|self $item): self
{
$this->items[] = $item;
return $this;
Expand All @@ -23,9 +18,10 @@ public function add($item): self
*/
public function getLeafNodes(): array
{
$nodes = array_map(function ($item) {
return $item instanceof self ? $item->getLeafNodes() : [$item];
}, $this->items);
$nodes = array_map(
static fn($item) => $item instanceof self ? $item->getLeafNodes() : [$item],
$this->items
);

return array_merge([], ...$nodes);
}
Expand Down
15 changes: 5 additions & 10 deletions src/Parser/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,16 @@

class Parser
{
private $createMissingPaths;
public $branched = false;
public bool $branched = false;

public function __construct($createMissingPaths = false)
public function __construct(private bool $createMissingPaths = false)
{
$this->createMissingPaths = $createMissingPaths;
}

public function parse(&$data, string $path): NodeList
public function parse(array|object &$data, string $path): NodeList
{
$segments = $this->getSegments($path);

$keys = array_map(function (Segment $segment) {
return $segment->key;
}, $segments);
$keys = array_map(static fn(Segment $segment) => $segment->key, $segments);

$this->branched = in_array('*', $keys);

Expand Down Expand Up @@ -72,7 +67,7 @@ private function getSegments(string $path): array
$segments = [];

foreach ($iterator as $index => $part) {
$segments[] = new Segment($part, $iterator[$index + 1] ?? Segment::DELIMITER_ARRAY);
$segments[] = new Segment($part, $iterator[$index + 1] ?? Segment::DELIMITER_ARRAY);
$iterator->next();
}

Expand Down
11 changes: 3 additions & 8 deletions src/Parser/Segment.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,10 @@

class Segment
{
const DELIMITER_ARRAY = '.';
const DELIMITER_OBJECT = '->';
public const DELIMITER_ARRAY = '.';
public const DELIMITER_OBJECT = '->';

public $key;
public $delimiter;

public function __construct(string $key, string $delimiter = self::DELIMITER_ARRAY)
public function __construct(public string $key, public string $delimiter = self::DELIMITER_ARRAY)
{
$this->key = $key;
$this->delimiter = $delimiter;
}
}
Loading