Browse Source

增加jsonq标签,方便调用api显示

tags/6.2.6
tianya 1 year ago
parent
commit
d7f0dc9366
13 changed files with 1808 additions and 3 deletions
  1. +2
    -2
      src/apps/digg_ajax.php
  2. +278
    -0
      src/system/libraries/jsonq/Condition.php
  3. +9
    -0
      src/system/libraries/jsonq/Exceptions/ConditionNotAllowedException.php
  4. +9
    -0
      src/system/libraries/jsonq/Exceptions/FileNotFoundException.php
  5. +9
    -0
      src/system/libraries/jsonq/Exceptions/InvalidJsonException.php
  6. +9
    -0
      src/system/libraries/jsonq/Exceptions/InvalidNodeException.php
  7. +9
    -0
      src/system/libraries/jsonq/Exceptions/NullValueException.php
  8. +644
    -0
      src/system/libraries/jsonq/JsonQueriable.php
  9. +741
    -0
      src/system/libraries/jsonq/Jsonq.php
  10. +7
    -0
      src/system/libraries/jsonq/Results/ValueNotFound.php
  11. +7
    -0
      src/system/taglib/help/jsonq.txt
  12. +1
    -1
      src/system/taglib/help/sql.txt
  13. +83
    -0
      src/system/taglib/jsonq.lib.php

+ 2
- 2
src/apps/digg_ajax.php View File

@@ -40,7 +40,7 @@ if (!is_array($row) || $cfg_digg_update == 0) {
}
DelCache($prefix, $key);
}
SetCache($prefix, $key, $row, 0);
SetCache($prefix, $key, $row);
} else {
if ($action == 'good') {
$row['goodpost'] = $row['goodpost'] + 1;
@@ -59,7 +59,7 @@ if (!is_array($row) || $cfg_digg_update == 0) {
DelCache($prefix, $key);
}
}
SetCache($prefix, $key, $row, 0);
SetCache($prefix, $key, $row);
}
$digg = '';
if (!is_array($row)) exit();


+ 278
- 0
src/system/libraries/jsonq/Condition.php View File

@@ -0,0 +1,278 @@
<?php
if (!defined('DEDEINC')) exit('dedebiz');
class Condition
{
/**
* Simple equals
*
* @param mixed $value
* @param mixed $comparable
*
* @return bool
*/
public static function equal($value, $comparable)
{
return $value == $comparable;
}

/**
* Strict equals
*
* @param mixed $value
* @param mixed $comparable
*
* @return bool
*/
public static function strictEqual($value, $comparable)
{
return $value === $comparable;
}

/**
* Simple not equal
*
* @param mixed $value
* @param mixed $comparable
*
* @return bool
*/
public static function notEqual($value, $comparable)
{
return $value != $comparable;
}

/**
* Strict not equal
*
* @param mixed $value
* @param mixed $comparable
*
* @return bool
*/
public static function strictNotEqual($value, $comparable)
{
return $value !== $comparable;
}

/**
* Strict greater than
*
* @param mixed $value
* @param mixed $comparable
*
* @return bool
*/
public static function greaterThan($value, $comparable)
{
return $value > $comparable;
}

/**
* Strict less than
*
* @param mixed $value
* @param mixed $comparable
*
* @return bool
*/
public static function lessThan($value, $comparable)
{
return $value < $comparable;
}

/**
* Greater or equal
*
* @param mixed $value
* @param mixed $comparable
*
* @return bool
*/
public static function greaterThanOrEqual($value, $comparable)
{
return $value >= $comparable;
}

/**
* Less or equal
*
* @param mixed $value
* @param mixed $comparable
*
* @return bool
*/
public static function lessThanOrEqual($value, $comparable)
{
return $value <= $comparable;
}

/**
* In array
*
* @param mixed $value
* @param array $comparable
*
* @return bool
*/
public static function in($value, $comparable)
{
return (is_array($comparable) && in_array($value, $comparable));
}

/**
* Not in array
*
* @param mixed $value
* @param array $comparable
*
* @return bool
*/
public static function notIn($value, $comparable)
{
return (is_array($comparable) && !in_array($value, $comparable));
}

/**
* Is null equal
*
* @param mixed $value
*
* @return bool
*/
public static function isNull($value, $comparable)
{
return is_null($value);
}

/**
* Is not null equal
*
* @param mixed $value
*
* @return bool
*/
public static function isNotNull($value, $comparable)
{
return !is_null($value);
}

/**
* Start With
*
* @param mixed $value
* @param string $comparable
*
* @return bool
*/
public static function startWith($value, $comparable)
{
if (is_array($comparable) || is_array($value) || is_object($comparable) || is_object($value)) {
return false;
}
if (preg_match("/^$comparable/", $value)) {
return true;
}

return false;
}

/**
* End with
*
* @param mixed $value
* @param string $comparable
*
* @return bool
*/
public static function endWith($value, $comparable)
{
if (is_array($comparable) || is_array($value) || is_object($comparable) || is_object($value)) {
return false;
}
if (preg_match("/$comparable$/", $value)) {
return true;
}

return false;
}

/**
* Match with pattern
*
* @param mixed $value
* @param string $comparable
*
* @return bool
*/
public static function match($value, $comparable)
{
if (is_array($comparable) || is_array($value) || is_object($comparable) || is_object($value)) {
return false;
}
$comparable = trim($comparable);

if (preg_match("/^$comparable$/", $value)) {
return true;
}

return false;
}

/**
* Contains substring in string
*
* @param string $value
* @param string $comparable
*
* @return bool
*/
public static function contains($value, $comparable)
{
return (strpos($value, $comparable) !== false);
}

/**
* Dates equal
*
* @param string $value
* @param string $comparable
*
* @return bool
*/
public static function dateEqual($value, $comparable, $format = 'Y-m-d')
{
$date = date($format, strtotime($value));
return $date == $comparable;
}

/**
* Months equal
*
* @param string $value
* @param string $comparable
*
* @return bool
*/
public static function monthEqual($value, $comparable)
{
$month = date('m', strtotime($value));
return $month == $comparable;
}

/**
* Years equal
*
* @param string $value
* @param string $comparable
*
* @return bool
*/
public static function yearEqual($value, $comparable)
{
$year = date('Y', strtotime($value));
return $year == $comparable;
}
}

+ 9
- 0
src/system/libraries/jsonq/Exceptions/ConditionNotAllowedException.php View File

@@ -0,0 +1,9 @@
<?php
if (!defined('DEDEINC')) exit('dedebiz');
class ConditionNotAllowedException extends \Exception
{
public function __construct($message = "Condition not allowed exception", $code = 0, \Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
}

+ 9
- 0
src/system/libraries/jsonq/Exceptions/FileNotFoundException.php View File

@@ -0,0 +1,9 @@
<?php
if (!defined('DEDEINC')) exit('dedebiz');
class FileNotFoundException extends \Exception
{
public function __construct($message = "File not found exception", $code = 0, \Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
}

+ 9
- 0
src/system/libraries/jsonq/Exceptions/InvalidJsonException.php View File

@@ -0,0 +1,9 @@
<?php
if (!defined('DEDEINC')) exit('dedebiz');
class InvalidJsonException extends \Exception
{
public function __construct($message = "Invalid JSON format", $code = 0, \Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
}

+ 9
- 0
src/system/libraries/jsonq/Exceptions/InvalidNodeException.php View File

@@ -0,0 +1,9 @@
<?php
if (!defined('DEDEINC')) exit('dedebiz');
class InvalidNodeException extends \Exception
{
public function __construct($message = "Invalid JSON node exception", $code = 0, \Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
}

+ 9
- 0
src/system/libraries/jsonq/Exceptions/NullValueException.php View File

@@ -0,0 +1,9 @@
<?php
if (!defined('DEDEINC')) exit('dedebiz');
class NullValueException extends \Exception
{
public function __construct($message = "Null value exception", $code = 0, \Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
}

+ 644
- 0
src/system/libraries/jsonq/JsonQueriable.php View File

@@ -0,0 +1,644 @@
<?php
if (!defined('DEDEINC')) exit('dedebiz');
require_once(dirname(__FILE__)."/Exceptions/ConditionNotAllowedException.php");
require_once(dirname(__FILE__)."/Exceptions/FileNotFoundException.php");
require_once(dirname(__FILE__)."/Exceptions/InvalidJsonException.php");
require_once(dirname(__FILE__)."/Results/ValueNotFound.php");
require_once(dirname(__FILE__)."/Condition.php");

trait JsonQueriable
{
/**
* store node path
* @var string|array
*/
protected $_node = '';

/**
* contain prepared data for process
* @var mixed
*/
protected $_map;

/**
* contains column names
* @var array
*/
protected $_select = [];

/**
* contains column names for except
* @var array
*/
protected $_except = [];

/**
* Stores base contents.
*
* @var array
*/
protected $_baseContents = [];

/**
* Stores all conditions.
*
* @var array
*/
protected $_conditions = [];

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

/**
* map all conditions with methods
* @var array
*/
protected static $_rulesMap = [
'=' => 'equal',
'eq' => 'equal',
'==' => 'strictEqual',
'seq' => 'strictEqual',
'!=' => 'notEqual',
'neq' => 'notEqual',
'!==' => 'strictNotEqual',
'sneq' => 'strictNotEqual',
'>' => 'greaterThan',
'gt' => 'greaterThan',
'<' => 'lessThan',
'lt' => 'lessThan',
'>=' => 'greaterThanOrEqual',
'gte' => 'greaterThanOrEqual',
'<=' => 'lessThanOrEqual',
'lte' => 'lessThanOrEqual',
'in' => 'in',
'notin' => 'notIn',
'null' => 'isNull',
'notnull' => 'isNotNull',
'startswith' => 'startWith',
'endswith' => 'endWith',
'match' => 'match',
'contains' => 'contains',
'dates' => 'dateEqual',
'month' => 'monthEqual',
'year' => 'yearEqual',
];


/**
* import data from file
*
* @param string|null $file
* @return bool
* @throws FileNotFoundException
* @throws InvalidJsonException
*/
public function import($file = null)
{
if (!is_null($file)) {
if (is_string($file)) {
$this->_map = $this->getDataFromFile($file);
$this->_baseContents = $this->_map;
return true;
}
}

throw new FileNotFoundException();
}

/**
* Prepare data from desire conditions
*
* @return $this
* @throws ConditionNotAllowedException
*/
protected function prepare()
{
if ($this->_isProcessed) {
return $this;
}

if (count($this->_conditions) > 0) {
$calculatedData = $this->processConditions();
$this->_map = $this->objectToArray($calculatedData);

$this->_conditions = [];
$this->_node = '';
$this->_isProcessed = true;
return $this;
}

$this->_isProcessed = true;
$this->_map = $this->objectToArray($this->getData());
return $this;
}

/**
* Our system will cache processed data and prevend multiple time processing. If
* you want to reprocess this method can help you
*
* @return $this
*/
public function reProcess()
{
$this->_isProcessed = false;
return $this;
}

/**
* Parse object to array
*
* @param object $obj
* @return array|mixed
*/
protected function objectToArray($obj)
{
if (!is_array($obj) && !is_object($obj)) {
return $obj;
}

if (is_array($obj)) {
return $obj;
}

if (is_object($obj)) {
$obj = get_object_vars($obj);
}

return array_map([$this, 'objectToArray'], $obj);
}

/**
* Check given value is multidimensional array
*
* @param array $arr
* @return bool
*/
protected function isMultiArray($arr)
{
if (!is_array($arr)) {
return false;
}

rsort($arr);

return isset($arr[0]) && is_array($arr[0]);
}

/**
* Check given value is valid JSON
*
* @param string $value
* @param bool $isReturnMap
*
* @return bool|array
*/
public function isJson($value, $isReturnMap = false)
{
if (is_array($value) || is_object($value)) {
return false;
}

$data = json_decode($value, true);

if (json_last_error() !== JSON_ERROR_NONE) {
return false;
}

return $isReturnMap ? $data : true;
}


public function takeColumn($array)
{
return $this->selectColumn($this->exceptColumn($array));
}

/**
* selecting specific column
*
* @param $array
* @return array
*/
protected function selectColumn($array)
{
$keys = $this->_select;

if (count($keys) == 0) {
return $array;
}

return array_intersect_key($array, array_flip((array) $keys));
}

/**
* selecting specific column
*
* @param $array
* @return array
*/
protected function exceptColumn($array)
{
$keys = $this->_except;

if (count($keys) == 0) {
return $array;
}

return array_diff_key($array, array_flip((array) $keys));
}


/**
* Prepare data for result
*
* @param mixed $data
* @param bool $isObject
* @return array|mixed
*/
protected function prepareResult($data, $isObject)
{
$output = [];

if (is_null($data) || is_scalar($data)) {
return $data;
}

if ($this->isMultiArray($data)) {
foreach ($data as $key => $val) {
$val = $this->takeColumn($val);
$output[$key] = $isObject ? (object) $val : $val;
}
} else {
$output = json_decode(json_encode($this->takeColumn($data)), $isObject);
}

return $output;
}

/**
* Read JSON data from file
*
* @param string $file
* @param string $type
* @return bool|string|array
* @throws FileNotFoundException
* @throws InvalidJsonException
*/
protected function getDataFromFile($file, $type = 'application/json')
{
$opts = [
'http' => [
'header' => 'Content-Type: '.$type.'; charset=utf-8',
],
];

$context = stream_context_create($opts);
$data = file_get_contents($file, 0, $context);
$json = $this->isJson($data, true);

if (!$json) {
throw new InvalidJsonException();
}

return $json;
}



/**
* Get data from nested array
*
* @param $map array
* @param $node string
* @return bool|array|mixed
*/
protected function getFromNested($map, $node)
{
if (empty($node) || $node == '.') {
return $map;
}

if ($node) {
$terminate = false;
$path = explode('.', $node);

foreach ($path as $val) {
if (!is_array($map)) return $map;

if (!array_key_exists($val, $map)) {
$terminate = true;
break;
}

$map = &$map[$val];
}

if ($terminate) {
return new ValueNotFound();
}

return $map;
}

return new ValueNotFound();
}

/**
* get data from node path
*
* @return mixed
*/
protected function getData()
{
return $this->getFromNested($this->_map, $this->_node);
}

/**
* process AND and OR conditions
*
* @return array|string|object
* @throws ConditionNotAllowedException
*/
protected function processConditions()
{
$data = $this->getData();
$conditions = $this->_conditions;
$result = array_filter($data, function ($val) use ($conditions) {
$res = false;
foreach ($conditions as $cond) {
$tmp = true;
foreach ($cond as $rule) {
$function = self::$_rulesMap[$rule['condition']];
if (!is_callable($function)) {
if (!method_exists(Condition::class, $function)) {
throw new ConditionNotAllowedException("Exception: $function condition not allowed");
}

$function = [Condition::class, $function];
}

$value = $this->getFromNested($val, $rule['key']);
$return = $value instanceof ValueNotFound ? false : call_user_func_array($function, [$value, $rule['value']]);
$tmp &= $return;
}
$res |= $tmp;
}
return $res;
});

return $result;
}

/**
* make WHERE clause
*
* @param string $key
* @param string $condition
* @param mixed $value
* @return $this
*/
public function where($key, $condition = null, $value = null)
{
if (!is_null($condition) && is_null($value)) {
$value = $condition;
$condition = '=';
}

if (count($this->_conditions) < 1) {
array_push($this->_conditions, []);
}
return $this->makeWhere($key, $condition, $value);
}

/**
* make WHERE clause with OR
*
* @param string $key
* @param string $condition
* @param mixed $value
* @return $this
*/
public function orWhere($key = null, $condition = null, $value = null)
{
if (!is_null($condition) && is_null($value)) {
$value = $condition;
$condition = '=';
}

array_push($this->_conditions, []);

return $this->makeWhere($key, $condition, $value);
}

/**
* generator for AND and OR where
*
* @param string $key
* @param string $condition
* @param mixed $value
* @return $this
*/
protected function makeWhere($key, $condition = null, $value = null)
{
$current = end($this->_conditions);
$index = key($this->_conditions);
if (is_callable($key)) {
$key($this);
return $this;
}

array_push($current, [
'key' => $key,
'condition' => $condition,
'value' => $value,
]);

$this->_conditions[$index] = $current;

return $this;
}

/**
* make WHERE IN clause
*
* @param string $key
* @param array $value
* @return $this
*/
public function whereIn($key = null, $value = [])
{
$this->where($key, 'in', $value);

return $this;
}

/**
* make WHERE NOT IN clause
*
* @param string $key
* @param mixed $value
* @return $this
*/
public function whereNotIn($key = null, $value = [])
{
$this->where($key, 'notin', $value);
return $this;
}

/**
* make WHERE NULL clause
*
* @param string $key
* @return $this
*/
public function whereNull($key = null)
{
$this->where($key, 'null', 'null');
return $this;
}


/**
* make WHERE Boolean clause
*
* @param string $key
* @return $this
*/
public function whereBool($key, $value)
{
if (is_bool($value)) {
$this->where($key, '==', $value);
}
return $this;
}

/**
* make WHERE NOT NULL clause
*
* @param string $key
* @return $this
*/
public function whereNotNull($key = null)
{
$this->where($key, 'notnull', 'null');

return $this;
}

/**
* make WHERE START WITH clause
*
* @param string $key
* @param string $value
* @return $this
*/
public function whereStartsWith($key, $value)
{
$this->where($key, 'startswith', $value);

return $this;
}

/**
* make WHERE ENDS WITH clause
*
* @param string $key
* @param string $value
* @return $this
*/
public function whereEndsWith($key, $value)
{
$this->where($key, 'endswith', $value);

return $this;
}

/**
* make WHERE MATCH clause
*
* @param string $key
* @param string $value
* @return $this
*/
public function whereMatch($key, $value)
{
$this->where($key, 'match', $value);

return $this;
}

/**
* make WHERE CONTAINS clause
*
* @param string $key
* @param string $value
* @return $this
*/
public function whereContains($key, $value)
{
$this->where($key, 'contains', $value);

return $this;
}

/**
* make WHERE DATE clause
*
* @param string $key
* @param string $value
* @return $this
*/
public function whereDate($key, $value)
{
$this->where($key, 'dates', $value);

return $this;
}

/**
* make WHERE month clause
*
* @param string $key
* @param string $value
* @return $this
*/
public function whereMonth($key, $value)
{
$this->where($key, 'month', $value);

return $this;
}

/**
* make WHERE Year clause
*
* @param string $key
* @param string $value
* @return $this
*/
public function whereYear($key, $value)
{
$this->where($key, 'year', $value);

return $this;
}

/**
* make macro for custom where clause
*
* @param string $name
* @param callable $fn
* @return bool
*/
public static function macro($name, callable $fn)
{
if (!in_array($name, self::$_rulesMap)) {
self::$_rulesMap[$name] = $fn;
return true;
}

return false;
}
}

+ 741
- 0
src/system/libraries/jsonq/Jsonq.php View File

@@ -0,0 +1,741 @@
<?php
if (!defined('DEDEINC')) exit('dedebiz');
require_once(dirname(__FILE__)."/Exceptions/ConditionNotAllowedException.php");
require_once(dirname(__FILE__)."/Exceptions/FileNotFoundException.php");
require_once(dirname(__FILE__)."/Exceptions/InvalidJsonException.php");
require_once(dirname(__FILE__)."/Exceptions/InvalidNodeException.php");
require_once(dirname(__FILE__)."/Exceptions/NullValueException.php");
require_once(dirname(__FILE__)."/JsonQueriable.php");


class Jsonq
{
use JsonQueriable;

/**
* this constructor set main json file path
* otherwise create it and read file contents
* and decode as an array and store it in $this->_data
*
* @param null $jsonFile
* @throws Exceptions\FileNotFoundException
* @throws InvalidJsonException
*/
public function __construct($jsonFile = null)
{
if (!is_null($jsonFile)) {
$this->import($jsonFile);
}
}

/**
* Deep copy current instance
*
* @return Jsonq
*/
public function copy()
{
return clone $this;
}

/**
* Set node path, where JsonQ start to prepare
*
* @param null $node
* @return $this
* @throws NullValueException
*/
public function from($node = null)
{
$this->_isProcessed = false;

if (is_null($node) || $node == '') {
throw new NullValueException("Null node exception");
}

$this->_node = $node;

return $this;
}

/**
* Alias of from() method
*
* @param null $node
* @return $this
* @throws NullValueException
*/
public function at($node = null)
{
return $this->from($node);
}

/**
* select desired column
*
* @param ... scalar
* @return $this
*/
public function select()
{
$args = func_get_args();
if (count($args) > 0 ){
$this->_select = $args;
}

return $this;
}

/**
* select desired column for except
*
* @param ... scalar
* @return $this
*/
public function except()
{
$args = func_get_args();
if (count($args) > 0 ){
$this->_except = $args;
}

return $this;
}

/**
* getting prepared data
*
* @param bool $object
* @return array|object
* @throws ConditionNotAllowedException
*/
public function get($object = false)
{
$this->prepare();

return $this->prepareResult($this->_map, $object);
}

/**
* alias of get method
*
* @param bool $object
* @return array|object
* @throws ConditionNotAllowedException
*/
public function fetch($object = true)
{
return $this->get($object);
}

/**
* check data exists in system
*
* @return bool
* @throws ConditionNotAllowedException
*/
public function exists()
{
$this->prepare();

return (!empty($this->_map) && !is_null($this->_map));
}

/**
* reset given data to the $_map
*
* @param mixed $data
* @param bool $instance
* @return jsonq
*/
public function reset($data = null, $instance = false)
{
if (!is_null($data)) {
$this->_baseContents = $data;
}

if ($instance) {
$self = new self();
$self->collect($this->_baseContents);

return $self;
}

$this->_map = $this->_baseContents;
$this->reProcess();

return $this;
}

/**
* getting group data from specific column
*
* @param string $column
* @return $this
* @throws ConditionNotAllowedException
*/
public function groupBy($column)
{
$this->prepare();

$data = [];
foreach ($this->_map as $map) {
$value = $this->getFromNested($map, $column);
if ($value) {
$data[$value][] = $map;
}
}

$this->_map = $data;
return $this;
}

public function countGroupBy($column)
{

$this->prepare();

$data = [];
foreach ($this->_map as $map) {
$value = $this->getFromNested($map, $column);
if (!$value) {
continue;
}

if (isset($data[$value])) {
$data[$value] ++;
} else {
$data[$value] = 1;
}
}

$this->_map = $data;
return $this;
}

/**
* count prepared data
*
* @return int
* @throws ConditionNotAllowedException
*/
public function count()
{
$this->prepare();

return count($this->_map);
}

/**
* size is an alias of count
*
* @return int
* @throws ConditionNotAllowedException
*/
public function size()
{
return $this->count();
}

/**
* sum prepared data
* @param int $column
* @return int
* @throws ConditionNotAllowedException
*/
public function sum($column = null)
{
$this->prepare();

$sum = 0;
if (is_null($column)) {
$sum = array_sum($this->_map);
} else {
foreach ($this->_map as $key => $val) {
$value = $this->getFromNested($val, $column);
if (is_scalar($value)) {
$sum += $value;
}

}
}

return $sum;
}

/**
* getting max value from prepared data
*
* @param int $column
* @return int
* @throws ConditionNotAllowedException
*/
public function max($column = null)
{
$this->prepare();

if (is_null($column)) {
$max = max($this->_map);
} else {
$max = max(array_column($this->_map, $column));
}

return $max;
}

/**
* getting min value from prepared data
*
* @param int $column
* @return string
* @throws ConditionNotAllowedException
*/
public function min($column = null)
{
$this->prepare();

if (is_null($column)) {
$min = min($this->_map);
} else {
$min = min(array_column($this->_map, $column));
}

return $min;
}

/**
* getting average value from prepared data
*
* @param int $column
* @return string
* @throws ConditionNotAllowedException
*/
public function avg($column = null)
{
$this->prepare();

$count = $this->count();
$total = $this->sum($column);

return ($total/$count);
}

/**
* getting first element of prepared data
*
* @param bool $object
* @return object|array|null
* @throws ConditionNotAllowedException
*/
public function first($object = false)
{
$this->prepare();

$data = $this->_map;
if (count($data) > 0) {
return $this->prepareResult(reset($data), $object);
}

return null;
}

/**
* getting last element of prepared data
*
* @param bool $object
* @return object|array|null
* @throws ConditionNotAllowedException
*/
public function last($object = false)
{
$this->prepare();

$data = $this->_map;
if (count($data) > 0) {
return $this->prepareResult(end($data), $object);
}

return null;
}

/**
* getting nth number of element of prepared data
*
* @param int $index
* @param bool $object
* @return object|array|null
* @throws ConditionNotAllowedException
*/
public function nth($index, $object = false)
{
$this->prepare();

$data = $this->_map;
$total_elm = count($data);
$idx = abs($index);

if (!is_integer($index) || $total_elm < $idx || $index == 0 || !is_array($this->_map)) {
return null;
}

if ($index > 0) {
$result = $data[$index - 1];
} else {
$result = $data[$this->count() + $index];
}

return $this->prepareResult($result, $object);
}

/**
* sorting from prepared data
*
* @param string $column
* @param string $order
* @return object|array|null
* @throws ConditionNotAllowedException
*/
public function sortBy($column, $order = 'asc')
{
$this->prepare();

if (!is_array($this->_map)) {
return $this;
}

usort($this->_map, function ($a, $b) use ($column, $order) {
$val1 = $this->getFromNested($a, $column);
$val2 = $this->getFromNested($b, $column);
if (is_string($val1)) {
$val1 = strtolower($val1);
}

if (is_string($val2)) {
$val2 = strtolower($val2);
}

if ($val1 == $val2) {
return 0;
}
$order = strtolower(trim($order));

if ($order == 'desc') {
return ($val1 > $val2) ? -1 : 1;
} else {
return ($val1 < $val2) ? -1 : 1;
}
});

return $this;
}

/**
* Sort prepared data using a custom sort function.
*
* @param callable $sortFunc
*
* @return object|array|null
* @throws ConditionNotAllowedException
*/
public function sortByCallable(callable $sortFunc)
{
$this->prepare();

if (!is_array($this->_map)) {
return $this;
}

usort($this->_map, $sortFunc);

return $this;
}

/**
* Sort an array value
*
* @param string $order
* @return Jsonq
*/
public function sort($order = 'asc')
{
if ($order == 'desc') {
rsort($this->_map);
}else{
sort($this->_map);
}

return $this;
}

/**
* getting data from desire path
*
* @param string $path
* @param bool $object
* @return mixed
* @throws NullValueException
* @throws ConditionNotAllowedException
*/
public function find($path, $object = false)
{
return $this->from($path)->prepare()->get($object);
}

/**
* take action of each element of prepared data
*
* @param callable $fn
* @throws ConditionNotAllowedException
*/
public function each(callable $fn)
{
$this->prepare();

foreach ($this->_map as $key => $val) {
$fn($key, $val);
}
}

/**
* transform prepared data by using callable function
*
* @param callable $fn
* @return object|array
* @throws ConditionNotAllowedException
*/
public function transform(callable $fn)
{
$this->prepare();

$new_data = [];
foreach ($this->_map as $key => $val) {
$new_data[$key] = $fn($val);
}

return $this->prepareResult($new_data, false);
}

/**
* pipe send output in next pipe
*
* @param callable $fn
* @param string|null $class
* @return object|array
* @throws ConditionNotAllowedException
*/
public function pipe(callable $fn, $class = null)
{
$this->prepare();

if (is_string($fn) && !is_null($class)) {
$instance = new $class;

$this->_map = call_user_func_array([$instance, $fn], [$this]);
return $this;
}

$this->_map = $fn($this);
return $this;
}

/**
* filtered each element of prepared data
*
* @param callable $fn
* @param bool $key
* @return mixed|array
* @throws ConditionNotAllowedException
*/
public function filter(callable $fn, $key = false)
{
$this->prepare();

$data = [];
foreach ($this->_map as $k => $val) {
if ($fn($val)) {
if ($key) {
$data[$k] = $val;
} else {
$data[] = $val;
}
}
}

return $this->prepareResult($data, false);
}

/**
* then method set position of working data
*
* @param string $node
* @return jsonq
* @throws NullValueException
* @throws ConditionNotAllowedException
*/
public function then($node)
{
$this->_map = $this->prepare()->first(false);

$this->from($node);

return $this;
}

/**
* import raw JSON data for process
*
* @param string $data
* @return jsonq
*/
public function json($data)
{
$json = $this->isJson($data, true);

if ($json) {
return $this->collect($json);
}

return $this;
}

/**
* import parsed data from raw json
*
* @param array|object $data
* @return jsonq
*/
public function collect($data)
{
$this->_map = $this->objectToArray($data);
$this->_baseContents = &$this->_map;

return $this;
}

/**
* implode resulting data from desire key and delimeter
*
* @param string|array $key
* @param string $delimiter
* @return string|array
* @throws ConditionNotAllowedException
*/
public function implode($key, $delimiter = ',')
{
$this->prepare();

$implode = [];
if (is_string($key)) {
return $this->makeImplode($key, $delimiter);
}

if (is_array($key)) {
foreach ($key as $k) {
$imp = $this->makeImplode($k, $delimiter);
$implode[$k] = $imp;
}

return $implode;
}
return '';
}

/**
* process implode from resulting data
*
* @param string $key
* @param string $delimiter
* @return string|null
*/
protected function makeImplode($key, $delimiter)
{
$data = array_column($this->_map, $key);

if (is_array($data)) {
return implode($delimiter, $data);
}

return null;
}

/**
* getting specific key's value from prepared data
*
* @param string $column
* @return object|array
* @throws ConditionNotAllowedException
*/
public function column($column)
{
$this->prepare();

return array_column($this->_map, $column);
}

/**
* getting raw JSON from prepared data
*
* @return string
* @throws ConditionNotAllowedException
*/
public function toJson()
{
$this->prepare();

return json_encode($this->_map);
}

/**
* getting all keys from prepared data
*
* @return object|array
* @throws ConditionNotAllowedException
*/
public function keys()
{
$this->prepare();

return array_keys($this->_map);
}

/**
* getting all values from prepared data
*
* @return object|array
* @throws ConditionNotAllowedException
*/
public function values()
{
$this->prepare();

return array_values($this->_map);
}

/**
* getting chunk values from prepared data
*
* @param int $amount
* @param $fn
* @return object|array|bool
* @throws ConditionNotAllowedException
*/
public function chunk($amount, callable $fn = null)
{
$this->prepare();

$chunk_value = array_chunk($this->_map, $amount);
$chunks = [];

if (!is_null($fn) && is_callable($fn)) {
foreach ($chunk_value as $chunk) {
$return = $fn($chunk);
if (!is_null($return)) {
$chunks[] = $return;
}
}
return count($chunks) > 0 ? $chunks : null;
}

return $chunk_value;
}
}

+ 7
- 0
src/system/libraries/jsonq/Results/ValueNotFound.php View File

@@ -0,0 +1,7 @@
<?php
if (!defined('DEDEINC')) exit('dedebiz');
/**
* This class represents a query result where a given
* value was queried but did not exist.
*/
class ValueNotFound {}

+ 7
- 0
src/system/taglib/help/jsonq.txt View File

@@ -0,0 +1,7 @@
JSONQ标签
>>dede>>
{dede:jsonq url='https://www.dedebiz.com/api/v1/ping' path='list' cachetime=3600}[field:id/] - [field:name/]<br/>{/dede:jsonq}
>>dede>>
url='' JSON接口地址
path='' 路径(可选),如果为空[field:path/]可获取指定path的值
cachetime=3600 缓存时间

+ 1
- 1
src/system/taglib/help/sql.txt View File

@@ -1,5 +1,5 @@
SQL标签
>>dede>>
{dede:sql sql=''}[field:title/]{/dede}
{dede:sql sql=''}[field:title/]{/dede:sql}
>>dede>>
sql='' 完整的SQL语句

+ 83
- 0
src/system/taglib/jsonq.lib.php View File

@@ -0,0 +1,83 @@
<?php

/**
* JSONQ标签
*
* @version $id:jsonq.lib.php 2023年3月20日 tianya $
* @package DedeBIZ.Taglib
* @copyright Copyright (c) 2022 DedeBIZ.COM
* @license https://www.dedebiz.com/license
* @link https://www.dedebiz.com
*/
require_once(DEDEINC . "/libraries/jsonq/Jsonq.php");
helper('cache');
function lib_jsonq(&$ctag, &$refObj)
{
$attlist = "url|,path|,cachetime|3600";
FillAttsDefault($ctag->CAttribute->Items, $attlist);
extract($ctag->CAttribute->Items, EXTR_SKIP);

$Innertext = trim($ctag->GetInnerText());

if ($url == '' || $Innertext == '') return '';
$key = md5($url);
try {
if ($path=='') {
$jsonq = new Jsonq($url);
$revalue = GetCache("tagjsonq2", $key);
if (!empty($revalue)) {
return $revalue;
}
$revalue = "";
$ctp = new DedeTagParse();
$ctp->SetNameSpace('field', '[', ']');
$ctp->LoadSource($Innertext);
foreach ($ctp->CTags as $tagid => $ctag) {
$tagname = $ctag->GetName();
$vv = $jsonq->from($tagname)->get();
$ctp->Assign($tagid, $vv);
$jsonq->reset();
}
$revalue .= $ctp->GetResult();
SetCache("tagjsonq2", $key, $revalue, $cachetime);
return $revalue;
}
$row = GetCache("tagjsonq", $key);
if (!is_array($row) || $cachetime == 0) {
$jsonq = new Jsonq($url);
$row = $jsonq->from($path)->get();
SetCache("tagjsonq", $key, $row, $cachetime);
}
if (!is_array($row)) {
return "";
}

$ctp = new DedeTagParse();
$ctp->SetNameSpace('field', '[', ']');
$ctp->LoadSource($Innertext);

$GLOBALS['autoindex'] = 0;
$revalue = "";

foreach ($row as $key => $value) {
$GLOBALS['autoindex']++;
foreach ($ctp->CTags as $tagid => $ctag) {
if ($ctag->GetName() == 'array') {
$ctp->Assign($tagid, $value);
} else {
if (!empty($value[$ctag->GetName()])) {
$ctp->Assign($tagid, $value[$ctag->GetName()]);
} else {
$ctp->Assign($tagid, "");
}
}
}
$revalue .= $ctp->GetResult();
}

return $revalue;
} catch (Exception $e) {
return "";
}
}

Loading…
Cancel
Save