@@ -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(); | |||
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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 {} |
@@ -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,5 +1,5 @@ | |||
SQL标签 | |||
>>dede>> | |||
{dede:sql sql=''}[field:title/]{/dede} | |||
{dede:sql sql=''}[field:title/]{/dede:sql} | |||
>>dede>> | |||
sql='' 完整的SQL语句 |
@@ -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 ""; | |||
} | |||
} |