Introduzione
Penso che la valutazione di query JSON simili a MongoDB in PHP abbia fornito tutte le informazioni di cui hai bisogno. tutto ciò di cui hai bisogno è essere creativo con la soluzione e ottenere ciò che desideri
La matrice
Supponiamo di avere il seguente json
convertito in 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);
Esempio 1
controlla se key
- Different
sarebbe semplice come
echo new ArrayCollection($array, array("key" => "Diffrent"));
Uscita
{"3":{"key":"Diffrent","value":"cool","children":{"tech":"json","lang":"php","year":2013}}}
Esempio 2 Controlla se release year
è 2013
echo new ArrayCollection($array, array("release.year" => 2013));
Uscita
{"2":{"name":"Mongo","type":"db","release":{"arch":"x86","version":23,"year":2013}}}
Esempio 3
Conta dove Year
è 2012
$c = new ArrayCollection($array, array("release.year" => 2012));
echo count($c); // output 2
Esempio 4
Prendiamo dal tuo esempio in cui vuoi controllare la version
è grater than 22
$c = new ArrayCollection($array, array("release.version" => array('$gt'=>22)));
echo $c;
Uscita
{"2":{"name":"Mongo","type":"db","release":{"arch":"x86","version":23,"year":2013}}}
Esempio 5
Controlla se release.arch
il valore è IN
un insieme come [x86,x100]
(Esempio)
$c = new ArrayCollection($array, array("release.arch" => array('$in'=>array("x86","x100"))));
foreach($c as $var)
{
print_r($var);
}
Uscita
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
)
)
Esempio 6
Utilizzando Callable
$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);
}
Uscita
Array
(
[name] => Mongo
[type] => db
[release] => Array
(
[arch] => x86
[version] => 23
[year] => 2013
)
)
Esempio 7
Registra il tuo nome di espressione
$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;
Uscita
{"2":{"name":"Mongo","type":"db","release":{"arch":"x86","version":23,"year":2013}}}
Classe usata
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);
}
}
Riepilogo
Potrebbe non coprire tutte le funzionalità avanzate e dovrebbe avere un'architettura estensibile
La classe sopra mostra un tipico esempio di ciò che vuoi .. puoi facilmente decouple
it , estendilo per supportare espressioni composte come $and
e $or
Gli oggetti espressione di query simili a MongoDB sono facili da comprendere e utilizzare, fornendo la possibilità di scrivere codice pulito e autoesplicativo, poiché sia la query che gli oggetti in cui cercare sono array associativi.
Perché non scrivere semplicemente l'array su un MongoDB
database piuttosto che lavorarlo array ?? È più efficiente e ti fa risparmiare un sacco di problemi
Devo anche ricordare che usa lo strumento migliore per il miglior lavoro ... Quello che vuoi è fondamentalmente una funzione di un Database
Fondamentalmente parlando è una comoda funzione per estrarre informazioni da array php. Conoscendo la struttura dell'array (l'arrayPath), consentirà di eseguire operazioni su dati di array multidimensionali, senza la necessità di più loop annidati.
L'esempio mostra come utilizzare un percorso per cercare il valore, ma dipendi ancora dal caricamento dell'array in memoria e dalla tua classe che esegue più ricorsioni e cicli che non sono efficienti come un database.
Apprezzo i suggerimenti sull'architettura, il codice correlato o simile, che può essere un esempio di buona pratica per creare al volo espressioni php "if..else".
Vuoi davvero dire che vuoi tutti quelli qui dentro ???