PHP Classes

File: src/JSONPath.php

Recommend this page to a friend!
  Classes of Sascha Greuel   PHP JSON Path   src/JSONPath.php   Download  
File: src/JSONPath.php
Role: Class source
Content type: text/plain
Description: Class source
Class: PHP JSON Path
Query values from data structures like XPATH
Author: By
Last change:
Date: 3 years ago
Size: 6,091 bytes
 

Contents

Class file image Download
<?php

/**
 * JSONPath implementation for PHP.
 *
 * @license https://github.com/SoftCreatR/JSONPath/blob/main/LICENSE MIT License
 */

declare(strict_types=1);

namespace
Flow\JSONPath;

use
ArrayAccess;
use
Countable;
use
Iterator;
use
JsonSerializable;

use function
array_merge;
use function
count;
use function
crc32;
use function
current;
use function
end;
use function
key;
use function
next;
use function
reset;

use const
E_USER_DEPRECATED;

class
JSONPath implements ArrayAccess, Iterator, JsonSerializable, Countable
{
    public const
ALLOW_MAGIC = true;

   
/**
     * @var array
     */
   
protected static $tokenCache = [];

   
/**
     * @var array
     */
   
protected $data = [];

   
/**
     * @var bool
     */
   
protected $options = false;

   
/**
     * @param array|ArrayAccess $data
     */
   
final public function __construct($data = [], bool $options = false)
    {
       
$this->data = $data;
       
$this->options = $options;
    }

   
/**
     * Evaluate an expression
     *
     * @throws JSONPathException
     *
     * @return static
     */
   
public function find(string $expression): self
   
{
       
$tokens = $this->parseTokens($expression);
       
$collectionData = [$this->data];

        foreach (
$tokens as $token) {
           
/** @var JSONPathToken $token */
           
$filter = $token->buildFilter($this->options);
           
$filteredDataList = [];

            foreach (
$collectionData as $value) {
                if (
AccessHelper::isCollectionType($value)) {
                   
$filteredDataList[] = $filter->filter($value);
                }
            }

            if (!empty(
$filteredDataList)) {
               
$collectionData = array_merge(...$filteredDataList);
            } else {
               
$collectionData = [];
            }
        }

        return new static(
$collectionData, $this->options);
    }

   
/**
     * @return mixed|null
     */
   
public function first()
    {
       
$keys = AccessHelper::collectionKeys($this->data);

        if (empty(
$keys)) {
            return
null;
        }

       
$value = $this->data[$keys[0]] ?? null;

        return
AccessHelper::isCollectionType($value) ? new static($value, $this->options) : $value;
    }

   
/**
     * Evaluate an expression and return the last result
     *
     * @return mixed|null
     */
   
public function last()
    {
       
$keys = AccessHelper::collectionKeys($this->data);

        if (empty(
$keys)) {
            return
null;
        }

       
$value = $this->data[end($keys)] ?: null;

        return
AccessHelper::isCollectionType($value) ? new static($value, $this->options) : $value;
    }

   
/**
     * Evaluate an expression and return the first key
     *
     * @return mixed|null
     */
   
public function firstKey()
    {
       
$keys = AccessHelper::collectionKeys($this->data);

        if (empty(
$keys)) {
            return
null;
        }

        return
$keys[0];
    }

   
/**
     * Evaluate an expression and return the last key
     *
     * @return mixed|null
     */
   
public function lastKey()
    {
       
$keys = AccessHelper::collectionKeys($this->data);

        if (empty(
$keys) || end($keys) === false) {
            return
null;
        }

        return
end($keys);
    }

   
/**
     * @throws JSONPathException
     */
   
public function parseTokens(string $expression): array
    {
       
$cacheKey = crc32($expression);

        if (isset(static::
$tokenCache[$cacheKey])) {
            return static::
$tokenCache[$cacheKey];
        }

       
$lexer = new JSONPathLexer($expression);
       
$tokens = $lexer->parseExpression();

        static::
$tokenCache[$cacheKey] = $tokens;

        return
$tokens;
    }

    public function
getData(): array
    {
        return
$this->data;
    }

   
/**
     * @deprecated Please use getData() instead
     */
   
public function data(): array
    {
       
trigger_error(
           
'Calling JSONPath::data() is deprecated, please use JSONPath::getData() instead.',
           
E_USER_DEPRECATED
       
);

        return
$this->getData();
    }

   
/**
     * @return mixed|null
     * @noinspection MagicMethodsValidityInspection
     */
   
public function __get($key)
    {
        return
$this->offsetExists($key) ? $this->offsetGet($key) : null;
    }

   
/**
     * @inheritDoc
     */
   
public function offsetExists($offset): bool
   
{
        return
AccessHelper::keyExists($this->data, $offset);
    }

   
/**
     * @inheritDoc
     */
   
public function offsetGet($offset)
    {
       
$value = AccessHelper::getValue($this->data, $offset);

        return
AccessHelper::isCollectionType($value)
            ? new static(
$value, $this->options)
            :
$value;
    }

   
/**
     * @inheritDoc
     */
   
public function offsetSet($offset, $value): void
   
{
        if (
$offset === null) {
           
$this->data[] = $value;
        } else {
           
AccessHelper::setValue($this->data, $offset, $value);
        }
    }

   
/**
     * @inheritDoc
     */
   
public function offsetUnset($offset): void
   
{
       
AccessHelper::unsetValue($this->data, $offset);
    }

   
/**
     * @inheritDoc
     */
   
public function jsonSerialize(): array
    {
        return
$this->getData();
    }

   
/**
     * @inheritDoc
     */
   
public function current()
    {
       
$value = current($this->data);

        return
AccessHelper::isCollectionType($value) ? new static($value, $this->options) : $value;
    }

   
/**
     * @inheritDoc
     */
   
public function next(): void
   
{
       
next($this->data);
    }

   
/**
     * @inheritDoc
     */
   
public function key()
    {
        return
key($this->data);
    }

   
/**
     * @inheritDoc
     */
   
public function valid(): bool
   
{
        return
key($this->data) !== null;
    }

   
/**
     * @inheritDoc
     */
   
public function rewind(): void
   
{
       
reset($this->data);
    }

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