Inleiding
Ik denk dat het evalueren van MongoDB-achtige JSON-query's in PHP alle informatie heeft gegeven die je nodig hebt. je hoeft alleen maar creatief te zijn met de oplossing en je bereikt wat je wilt
De array
Laten we aannemen dat we de volgende json
. hebben geconverteerd naar array
$json = '[{
"name":"Mongo",
"type":"db",
"release":{
"arch":"x86",
"version":22,
"year":2012
}
},
{
"name":"Mongo",
"type":"db",
"release":{
"arch":"x64",
"version":21,
"year":2012
}
},
{
"name":"Mongo",
"type":"db",
"release":{
"arch":"x86",
"version":23,
"year":2013
}
},
{
"key":"Diffrent",
"value":"cool",
"children":{
"tech":"json",
"lang":"php",
"year":2013
}
}
]';
$array = json_decode($json, true);
Voorbeeld 1
controleer of key
- Different
zou zo simpel zijn als
echo new ArrayCollection($array, array("key" => "Diffrent"));
Uitgang
{"3":{"key":"Diffrent","value":"cool","children":{"tech":"json","lang":"php","year":2013}}}
Voorbeeld 2 Controleer of release year
is 2013
echo new ArrayCollection($array, array("release.year" => 2013));
Uitgang
{"2":{"name":"Mongo","type":"db","release":{"arch":"x86","version":23,"year":2013}}}
Voorbeeld 3
Tel waar Year
is 2012
$c = new ArrayCollection($array, array("release.year" => 2012));
echo count($c); // output 2
Voorbeeld 4
Laten we uit uw voorbeeld nemen waar u version
wilt controleren is grater than 22
$c = new ArrayCollection($array, array("release.version" => array('$gt'=>22)));
echo $c;
Uitgang
{"2":{"name":"Mongo","type":"db","release":{"arch":"x86","version":23,"year":2013}}}
Voorbeeld 5
Controleer of release.arch
waarde is IN
een set zoals [x86,x100]
(Voorbeeld)
$c = new ArrayCollection($array, array("release.arch" => array('$in'=>array("x86","x100"))));
foreach($c as $var)
{
print_r($var);
}
Uitgang
Array
(
[name] => Mongo
[type] => db
[release] => Array
(
[arch] => x86
[version] => 22
[year] => 2012
)
)
Array
(
[name] => Mongo
[type] => db
[release] => Array
(
[arch] => x86
[version] => 23
[year] => 2013
)
)
Voorbeeld 6
Oproepbaar gebruiken
$year = 2013;
$expression = array("release.year" => array('$func' => function ($value) use($year) {
return $value === 2013;
}));
$c = new ArrayCollection($array, $expression);
foreach ( $c as $var ) {
print_r($var);
}
Uitgang
Array
(
[name] => Mongo
[type] => db
[release] => Array
(
[arch] => x86
[version] => 23
[year] => 2013
)
)
Voorbeeld 7
Registreer uw eigen uitdrukkingsnaam
$c = new ArrayCollection($array, array("release.year" => array('$baba' => 3)), false);
$c->register('$baba', function ($a, $b) {
return substr($a, - 1) == $b;
});
$c->parse();
echo $c;
Uitgang
{"2":{"name":"Mongo","type":"db","release":{"arch":"x86","version":23,"year":2013}}}
Klasse gebruikt
class ArrayCollection implements IteratorAggregate, Countable, JsonSerializable {
private $array;
private $found = array();
private $log;
private $expression;
private $register;
function __construct(array $array, array $expression, $parse = true) {
$this->array = $array;
$this->expression = $expression;
$this->registerDefault();
$parse === true and $this->parse();
}
public function __toString() {
return $this->jsonSerialize();
}
public function jsonSerialize() {
return json_encode($this->found);
}
public function getIterator() {
return new ArrayIterator($this->found);
}
public function count() {
return count($this->found);
}
public function getLog() {
return $this->log;
}
public function register($offset, $value) {
if (strpos($offset, '$') !== 0)
throw new InvalidArgumentException('Expresiion name must always start with "$" sign');
if (isset($this->register[$offset]))
throw new InvalidArgumentException(sprintf('Expression %s already registred .. Please unregister It first'));
if (! is_callable($value)) {
throw new InvalidArgumentException(sprintf('Only callable value can be registred'));
}
$this->register[$offset] = $value;
}
public function unRegister($offset) {
unset($this->register[$offset]);
}
public function parse() {
$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($this->array));
foreach ( $it as $k => $items ) {
if ($this->evaluate($this->getPath($it), $items)) {
$this->found[$it->getSubIterator(0)->key()] = $this->array[$it->getSubIterator(0)->key()];
}
}
}
private function registerDefault() {
$this->register['$eq'] = array($this,"evaluateEqal");
$this->register['$not'] = array($this,"evaluateNotEqual");
$this->register['$gte'] = array($this,"evaluateGreater");
$this->register['$gt'] = array($this,"evaluateGreater");
$this->register['$lte'] = array($this,"evaluateLess");
$this->register['$lt'] = array($this,"evaluateLess");
$this->register['$in'] = array($this,"evalueateInset");
$this->register['$func'] = array($this,"evalueateFunction");
$this->register['$fn'] = array($this,"evalueateFunction");
$this->register['$f'] = array($this,"evalueateFunction");
}
private function log($log) {
$this->log[] = $log;
}
private function getPath(RecursiveIteratorIterator $it) {
$keyPath = array();
foreach ( range(1, $it->getDepth()) as $depth ) {
$keyPath[] = $it->getSubIterator($depth)->key();
}
return implode(".", $keyPath);
}
private function checkType($a, $b) {
if (gettype($a) != gettype($b)) {
$this->log(sprintf("%s - %s is not same type of %s - %s", json_encode($a), gettype($a), json_encode($b), gettype($b)));
return false;
}
return true;
}
private function evaluate($key, $value) {
$o = $r = 0; // Obigation & Requirement
foreach ( $this->expression as $k => $options ) {
if ($k !== $key)
continue;
if (is_array($options)) {
foreach ( $options as $eK => $eValue ) {
if (strpos($eK, '$') === 0) {
$r ++;
$callable = $this->register[$eK];
$callable($value, $eValue) and $o ++;
} else {
throw new InvalidArgumentException('Missing "$" in expession key');
}
}
} else {
$r ++;
$this->evaluateEqal($value, $options) and $o ++;
}
}
return $r > 0 && $o === $r;
}
private function evaluateEqal($a, $b) {
return $a == $b;
}
private function evaluateNotEqual($a, $b) {
return $a != $b;
}
private function evaluateLess($a, $b) {
return $this->checkType($a, $b) and $a < $b;
}
private function evaluateGreater($a, $b) {
return $this->checkType($a, $b) and $a > $b;
}
private function evalueateInset($a, array $b) {
return in_array($a, $b);
}
private function evalueateFunction($a, callable $b) {
return $b($a);
}
}
Samenvatting
Het dekt mogelijk niet alle geavanceerde functies en zou een uitbreidbare architectuur moeten hebben
De bovenstaande klasse toont een typisch voorbeeld van wat je wilt .. je kunt gemakkelijk decouple
it , breid het uit om samengestelde uitdrukkingen zoals $and
. te ondersteunen en $or
MongoDB-achtige query-expressie-objecten zijn gemakkelijk te begrijpen en te gebruiken, en bieden de mogelijkheid om schone, zelfverklarende code te schrijven, omdat zowel de query als de objecten om in te zoeken associatieve arrays zijn.
Waarom schrijf je de array niet gewoon naar een MongoDB
database in plaats van te werken in arrays ?? Het is efficiënter en het zou u veel problemen besparen
Ik moet ook vermelden dat gebruik de beste tool voor de beste baan ... Wat je wilt is in feite een functie van een database
Eigenlijk is het een handige functie om informatie uit php-arrays te extraheren. Als u de arraystructuur kent (het arrayPath), kunt u bewerkingen uitvoeren op multidimensionale arraygegevens, zonder dat er meerdere geneste lussen nodig zijn.
Het voorbeeld laat zien hoe u een pad gebruikt om naar waarde te zoeken, maar u bent nog steeds afhankelijk van het laden van de array in het geheugen en uw klasse die meerdere recursie- en lussen uitvoert, wat niet zo efficiënt is als een database.
Ik waardeer architectuurtips, gerelateerde of vergelijkbare code, die een goed praktijkvoorbeeld kunnen zijn om php "if..else"-expressies on-the-fly te bouwen.
Bedoel je echt dat je al die mensen hier gewoon wilt hebben ???