Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get JSON Variable #4080

Merged
merged 3 commits into from
Jan 28, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 41 additions & 1 deletion system/HTTP/IncomingRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ public function isSecure(): bool
//--------------------------------------------------------------------

/**
* Fetch an item from the $_REQUEST object. This is the simplest way
* Fetch an item from the $_REQUEST object or a JSON input stream. This is the simplest way
* to grab data from the request object and can be used in lieu of the
* other get* methods in most cases.
*
Expand All @@ -300,6 +300,26 @@ public function isSecure(): bool
*/
public function getVar($index = null, $filter = null, $flags = null)
{
if ($this->isJSON())
{
if (is_null($index))
{
return $this->getJSON();
}

if (is_array($index))
{
$output = [];
foreach ($index as $key)
{
$output[$key] = $this->getJsonVar($key);
}
return $output;
}

return $this->getJsonVar($index);
}

return $this->fetchGlobal('request', $index, $filter, $flags);
}

Expand All @@ -325,6 +345,26 @@ public function getJSON(bool $assoc = false, int $depth = 512, int $options = 0)
return json_decode($this->body, $assoc, $depth, $options);
}

/**
* Get a specific variable from a JSON input stream
*
* @param string $index The variable that you want which can use dot syntax for getting specific values.
* @param boolean $assoc If true, return the result as an associative array.
*
* @return mixed
*/
public function getJsonVar(string $index, bool $assoc = false)
{
helper('array');

$data = dot_array_search($index, $this->getJSON(true));
if (is_array($data) && ! $assoc)
{
return json_decode(json_encode($data));
}
return $data;
}

//--------------------------------------------------------------------

/**
Expand Down
2 changes: 1 addition & 1 deletion system/HTTP/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public function getProtocolVersion(): string
*
* @deprecated Use header calls directly
*/
public function isJSON()
public function isJSON(): bool
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert this

Suggested change
public function isJSON(): bool
public function isJSON()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@samsonasik Just so I know in the future, can you tell me why this needed to be reverted? There are plenty of places where return types are being used in the framework and this function is meant to only return a boolean.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change return type declaration is BC break https://3v4l.org/YHmT2

Copy link
Collaborator

@iRedds iRedds Feb 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@samsonasik The method must explicitly return a boolean value.
This method and its changes were added to the development branch between the 4.0.4 and 4.1.0 (4.0.5) releases. So it cannot be BC.
Your example is not a BC, but a bad practice implementation.

What you did was a slap in the face. "I'm the boss. You're a fool "(с)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method marked as @deprecated so changing return type is not make sense.It may considered to be removed entirely instead.

The example is BC break, once we define public/protected method on non-final class, we need to maintain that.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method has been marked as @deprecated but has never been included in any release. It could just as easily have been removed. There is no reason to mark it as @depratacted.

The framework core does not override this method, so BC cannot be.
I repeat. This method was not available until release 4.1.
But suddenly he began to break something.

Stop justifying insanity!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@iRedds could you provide a PR to remove this? Thank you.

{
if (! $this->hasHeader('Content-Type'))
{
Expand Down
71 changes: 71 additions & 0 deletions tests/system/HTTP/IncomingRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,77 @@ public function testCanGrabGetRawJSON()
$this->assertEquals($expected, $request->getJSON(true));
}

public function testCanGetAVariableFromJson()
{
$jsonObj = [
'foo' => 'bar',
'baz' => [
'fizz' => 'buzz',
],
];
$json = json_encode($jsonObj);

$config = new App();
$config->baseURL = 'http://example.com/';

$request = new IncomingRequest($config, new URI(), $json, new UserAgent());

$this->assertEquals('bar', $request->getJsonVar('foo'));
$jsonVar = $request->getJsonVar('baz');
$this->assertIsObject($jsonVar);
$this->assertEquals('buzz', $jsonVar->fizz);
$this->assertEquals('buzz', $request->getJsonVar('baz.fizz'));
}

public function testGetJsonVarAsArray()
{
$jsonObj = [
'baz' => [
'fizz' => 'buzz',
'foo' => 'bar',
],
];
$json = json_encode($jsonObj);

$config = new App();
$config->baseURL = 'http://example.com/';

$request = new IncomingRequest($config, new URI(), $json, new UserAgent());

$jsonVar = $request->getJsonVar('baz', true);
$this->assertIsArray($jsonVar);
$this->assertEquals('buzz', $jsonVar['fizz']);
$this->assertEquals('bar', $jsonVar['foo']);
}

public function testGetVarWorksWithJson()
{
$jsonObj = [
'foo' => 'bar',
'fizz' => 'buzz',
];
$json = json_encode($jsonObj);

$config = new App();
$config->baseURL = 'http://example.com/';

$request = new IncomingRequest($config, new URI(), $json, new UserAgent());
$request->setHeader('Content-Type', 'application/json');

$this->assertEquals('bar', $request->getVar('foo'));
$this->assertEquals('buzz', $request->getVar('fizz'));

$multiple = $request->getVar(['foo', 'fizz']);
$this->assertIsArray($multiple);
$this->assertEquals('bar', $multiple['foo']);
$this->assertEquals('buzz', $multiple['fizz']);

$all = $request->getVar();
$this->assertIsObject($all);
$this->assertEquals('bar', $all->foo);
$this->assertEquals('buzz', $all->fizz);
}

public function testCanGrabGetRawInput()
{
$rawstring = 'username=admin001&role=administrator&usepass=0';
Expand Down
39 changes: 39 additions & 0 deletions user_guide_src/source/incoming/incomingrequest.rst
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,45 @@ arrays, pass in ``true`` as the first parameter.
The second and third parameters match up to the ``depth`` and ``options`` arguments of the
`json_decode <https://www.php.net/manual/en/function.json-decode.php>`_ PHP function.

If the incoming request has a ``CONTENT_TYPE`` header set to "application/json", you can also use ``getVar()`` to get
the JSON stream. Using ``getVar()`` in this way will always return an object.

**Get Specific Data from JSON**

You can get a specific piece of data from a JSON stream by passing a variable name into ``getVar()`` for the
data that you want or you can use "dot" notation to dig into the JSON to get data that is not on the root level.

::

//With a request body of:
{
"foo": "bar",
"fizz": {
"buzz": "baz"
}
}
$data = $request->getVar('foo');
//$data = "bar"

$data = $request->getVar('fizz.buzz');
//$data = "baz"


If you want the result to be an associative array instead of an object, you can use ``getJsonVar()`` instead and pass
true in the second parameter. This function can also be used if you can't guarantee that the incoming request will have the
correct ``CONTENT_TYPE`` header.

::

//With the same request as above
$data = $request->getJsonVar('fizz');
//$data->buzz = "baz"

$data = $request->getJsonVar('fizz', true);
//$data = ["buzz" => "baz"]

.. note:: See the documentation for ``dot_array_search()`` in the ``Array`` helper for more information on "dot" notation.

**Retrieving Raw data (PUT, PATCH, DELETE)**

Finally, you can grab the contents of php://input as a raw stream with ``getRawInput()``::
Expand Down