Upgrade to 3.2.0

This commit is contained in:
Bastian Allgeier
2019-06-25 09:56:08 +02:00
parent 9e18cf635d
commit 9c89153d35
296 changed files with 14408 additions and 2504 deletions

View File

@@ -9,11 +9,22 @@ namespace Kirby\Toolkit;
*
* @package Kirby Toolkit
* @author Bastian Allgeier <bastian@getkirby.com>
* @link http://getkirby.com
* @copyright Bastian Allgeier
* @link https://getkirby.com
* @copyright Bastian Allgeier GmbH
* @license https://opensource.org/licenses/MIT
*/
class Query
{
const PARTS = '!([a-zA-Z_]*(\(.*?\))?)\.|' . self::SKIP . '!';
const METHOD = '!\((.*)\)!';
const PARAMETERS = '!,|' . self::SKIP . '!';
const NO_PNTH = '\([^\(]+\)(*SKIP)(*FAIL)';
const NO_SQBR = '\[[^]]+\](*SKIP)(*FAIL)';
const NO_DLQU = '\"[^"]+\"(*SKIP)(*FAIL)';
const NO_SLQU = '\'[^\']+\'(*SKIP)(*FAIL)';
const SKIP = self::NO_PNTH . '|' . self::NO_SQBR . '|' .
self::NO_DLQU . '|' . self::NO_SLQU;
/**
* The query string
@@ -33,7 +44,7 @@ class Query
* Creates a new Query object
*
* @param string $query
* @param array $data
* @param array|object $data
*/
public function __construct(string $query = null, $data = [])
{
@@ -53,13 +64,25 @@ class Query
return $this->data;
}
$parts = $this->parts($this->query);
return $this->resolve($this->query);
}
/**
* Resolves the query if anything
* can be found. Otherwise returns null.
*
* @param string $query
* @return mixed
*/
protected function resolve(string $query)
{
$parts = $this->parts($query);
$data = $this->data;
$value = null;
while (count($parts)) {
$part = array_shift($parts);
$info = $this->info($part);
$info = $this->part($part);
$method = $info['method'];
$value = null;
@@ -86,64 +109,90 @@ class Query
/**
* Breaks the query string down into its components
*
* @param string $token
* @param string $query
* @return array
*/
protected function parts(string $token): array
protected function parts(string $query): array
{
$token = trim($token);
$token = preg_replace_callback('!\((.*?)\)!', function ($match) {
return '(' . str_replace('.', '@@@', $match[1]) . ')';
}, $token);
$query = trim($query);
$parts = explode('.', $token);
// match all parts but the last
preg_match_all(self::PARTS, $query, $match);
return $parts;
// remove all matched parts from the query to retrieve last part
foreach ($match[0] as $part) {
$query = Str::after($query, $part);
}
array_push($match[1], $query);
return $match[1];
}
/**
* Analyzes each part of the query string and
* extracts methods and method arguments.
*
* @param string $token
* @param string $part
* @return array
*/
protected function info(string $token): array
protected function part(string $part): array
{
$args = [];
$method = preg_replace_callback('!\((.*?)\)!', function ($match) use (&$args) {
$args = array_map(function ($arg) {
$arg = trim($arg);
$arg = str_replace('@@@', '.', $arg);
if (substr($arg, 0, 1) === '"') {
return trim($arg, '"');
}
if (substr($arg, 0, 1) === '\'') {
return trim($arg, '\'');
}
switch ($arg) {
case 'null':
return null;
case 'false':
return false;
case 'true':
return true;
}
if (is_numeric($arg) === true) {
return (float)$arg;
}
return $arg;
}, str_getcsv($match[1], ','));
}, $token);
$method = preg_replace_callback(self::METHOD, function ($match) use (&$args) {
$args = preg_split(self::PARAMETERS, $match[1]);
$args = array_map('self::parameter', $args);
}, $part);
return [
'method' => $method,
'args' => $args
];
}
/**
* Converts a parameter of query to
* proper type.
*
* @param mixed $arg
* @return mixed
*/
protected function parameter($arg)
{
$arg = trim($arg);
// string with double quotes
if (substr($arg, 0, 1) === '"') {
return trim($arg, '"');
}
// string with single quotes
if (substr($arg, 0, 1) === '\'') {
return trim($arg, '\'');
}
// boolean or null
switch ($arg) {
case 'null':
return null;
case 'false':
return false;
case 'true':
return true;
}
// numeric
if (is_numeric($arg) === true) {
return (float)$arg;
}
// array: split and recursive sanitizing
if (substr($arg, 0, 1) === '[' && substr($arg, -1) === ']') {
$arg = substr($arg, 1, -1);
$arg = preg_split(self::PARAMETERS, $arg);
return array_map('self::parameter', $arg);
}
// resolve parameter for objects and methods itself
return $this->resolve($arg);
}
}