From 36861fb37e329cd060e741ec14a7f1643194706a Mon Sep 17 00:00:00 2001 From: Zachary Tong Date: Fri, 11 Jul 2014 12:30:46 -0400 Subject: [PATCH] [DOCS] Add explanation of common JSON patterns in PHP --- docs/index.asciidoc | 2 + docs/php_json_objects.asciidoc | 161 +++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 docs/php_json_objects.asciidoc diff --git a/docs/index.asciidoc b/docs/index.asciidoc index eab121d76..7784d9af7 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -9,6 +9,8 @@ include::installation.asciidoc[] include::configuration.asciidoc[] +include::php_json_objects.asciidoc[] + include::index-operations.asciidoc[] include::indexing-operations.asciidoc[] diff --git a/docs/php_json_objects.asciidoc b/docs/php_json_objects.asciidoc new file mode 100644 index 000000000..ac8b1421a --- /dev/null +++ b/docs/php_json_objects.asciidoc @@ -0,0 +1,161 @@ + +== Dealing with JSON Arrays and Objects in PHP + +A common source of confusion with the client revolves around JSON arrays and objects, and how to specify them in PHP. +In particular, problems are caused by empty objects and arrays of objects. This page will show you some common patterns +used in Elasticsearch JSON API, and how to convert that to a PHP representation + +=== Empty Objects + +The Elasticsearch API uses empty JSON objects in several locations, and this can cause problems for PHP. Unlike other +languages, PHP does not have a "short" notation for empty objects and so many developers are unaware how to specify +an empty object. + +Consider adding a Highlight to a query: + +[source,json] +---- +{ + "query" : { + "match" : { + "content" : "quick brown fox" + } + }, + "highlight" : { + "fields" : { + "content" : {} <1> + } + } +} +---- +<1> This empty JSON object is what causes problems. + +The problem is that PHP will automatically convert `"content" : {}` into `"content" : []`, which is no longer valid +Elasticsearch DSL. We need to tell PHP that the empty object is explicitly an object, not an array. To define this +query in PHP, you would do: + +[source,json] +---- +$params['body'] = array( + 'query' => array( + 'match' => array( + 'content' => 'quick brown fox' + ) + ), + 'highlight' => array( + 'fields' => array( + 'content' => new \stdClass() <1> + ) + ) +); +$results = $client->search($params); +---- +<1> We use the generic PHP stdClass object to represent an empty object. The JSON will now encode correctly. + +By using an explicit stdClass object, we can force the `json_encode` parser to correctly output an empty object, instead +of an empty array. Sadly, this verbose solution is the only way to acomplish the goal in PHP...there is no "short" +version of an empty object. + +=== Arrays of Objects + +Another common pattern in Elasticsearch DSL is an array of objects. For example, consider adding a sort to your query: + +[source,json] +---- +{ + "query" : { + "match" : { "content" : "quick brown fox" } + }, + "sort" : [ <1> + {"time" : {"order" : "desc"}}, + {"popularity" : {"order" : "desc"}} + ] +} +---- +<1> "sort" contains an array of JSON objects + +This arrangement is *very* common, but the construction in PHP can be tricky since it requires nesting arrays. The +verbosity of PHP tends to obscure what is actually going on. To construct an array of objects, you actually need +an array of arrays: + +[source,json] +---- +$params['body'] = array( + 'query' => array( + 'match' => array( + 'content' => 'quick brown fox' + ) + ), + 'sort' => array( <1> + array('time' => array('order' => 'desc')), <2> + array('popularity' => array('order' => 'desc')) <3> + ) +); +$results = $client->search($params); +---- +<1> This array encodes the `"sort" : []` array +<2> This array encodes the `{"time" : {"order" : "desc"}}` object +<3> This array encodes the `{"popularity" : {"order" : "desc"}}` object + +If you are on PHP 5.4+, I would strongly encourage you to use the short array syntax. It makes these nested arrays +much simpler to read: + +[source,json] +---- +$params['body'] = [ + 'query' => [ + 'match' => [ + 'content' => 'quick brown fox' + ] + ], + 'sort' => [ + ['time' => ['order' => 'desc']], + ['popularity' => ['order' => 'desc']] + ] +]; +$results = $client->search($params); +---- + +=== Arrays of empty objects + +Occasionally, you'll encounter DSL that requires both of the previous patterns. The function score query is a good +example, it sometimes requires an array of objects, and some of those objects might be empty JSON objects. + +Given this query: +[source,json] +---- +{ + "query":{ + "function_score":{ + "functions":[ + { + "random_score":{} + } + ], + "boost_mode":"replace" + } + } +} +---- + +We can build it using the following PHP code: + + +[source,json] +---- +$params['body'] = array( + 'query' => array( + 'function_score' => array( + 'functions' => array( <1> + array( <2> + 'random_score' => new \stdClass() <3> + ) + ) + ) + ) +); +$results = $client->search($params); +---- +<1> This encodes the array of objects: `"functions" : []` +<2> This encodes an object inside the array: `{ "random_score": {} }` +<3> This encodes the empty JSON object: `"random_score": {}` \ No newline at end of file