Nette\Utils\Json::encode a JSON_FORCE_OBJECT

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Ajax
Člen | 59
+
0
-

Ahoj!

Potřebuju vrátit JSON s textovými indexy pole. Pochopil jsem, že nette na to nemá response, napsal jsem si vlastní:

class JsonTextKeysResponse implements \Nette\Application\IResponse
{

	/** @var array|\stdClass */
    private $payload;

    /** @var string */
    private $contentType;

	public function __construct($payload, $contentType = NULL) {
		if(!is_array($payload) && !is_object($payload)) {
			throw new Nette\InvalidArgumentException(sprintf('Payload must be array or object class, %s given.', gettype($payload)));
		}

		$this->payload = $payload;
		$this->contentType = $contentType ? $contentType : 'application/json';
	}

	public function send(Nette\Http\IRequest $httpRequest, Nette\Http\IResponse $httpResponse) {
		$httpResponse->setContentType($this->contentType);
		$httpResponse->setExpiration(FALSE);
		echo Nette\Utils\Json::encode($this->payload, JSON_FORCE_OBJECT);
	}
}

Problém je, že nette Nette\Utils\Json::encode nebere ten flag JSON_FORCE_OBJECT. Nevíte jak to obejít?

integer
Člen | 6
+
+3
-

Nejlepší by bylo asi poslat PR do Nette, který tuhle volbu umožní. Podle zdrojáků by to nejspíš byla úprava na jeden řádek (podobný tomuto https://api.nette.org/…son.php.html#33 ) a testy.

Jinak generování objektu místo prázdného pole by ti mělo zařídit přetypování prázdného pole na object pomocí (object) $emptyPayloadPart, ale vyžaduje si to nějaké ruční úpravy a procházení payloadu.

Takže nejrychlejší řešení je asi místo \Nette\Utils\Json::encode() zavolat syrové json_encode přímo z PHP. Pokud aplikace neběží na nějaké historické verzi php, tak by to neměl být větší problém.

Pavel Kravčík
Člen | 1196
+
+1
-

https://github.com/…ils/pull/152, https://github.com/…ils/pull/106

Asi nejlepší bude použít standardní php json jak píše @integer. Nette se v tomhle chová trochu nestandardně – tj. jinak než dokumentace.

Jan Tvrdík
Nette guru | 2595
+
+2
-

@Ajax JSON_FORCE_OBJECT je antipattern. Správné řešení je tam místo [] dát (object) [].

Ajax
Člen | 59
+
0
-

Jan Tvrdík napsal(a):

@Ajax JSON_FORCE_OBJECT je antipattern. Správné řešení je tam místo [] dát (object) [].

Problém je, že to nevyřeší můj problém. Potřebuju aby číselné indexy polí byly číslo-string, tedy

[
	1 => 'aaa',
	2 => 'bbb'
]

se do jsonu přepsalo takto

{
	"1": "aaa",
	"2": "bbb"
}

Toto mi konstrukce (object)$this->payload neudělá…

Editoval Ajax (19. 10. 2017 21:08)

CZechBoY
Člen | 3608
+
0
-

json neumi integerovy klice

Ajax
Člen | 59
+
0
-

Já vim, proto je potřebuju jako string. JSON_FORCE_OBJECT to zvládne, (object) ne.

Editoval Ajax (20. 10. 2017 9:48)

CZechBoY
Člen | 3608
+
0
-

Vůbec nechápu tvůj aktuální problém
https://3v4l.org/RR3ZS
https://3v4l.org/U7QGX

Ajax
Člen | 59
+
0
-

Tohle:

echo json_encode((object)["set" => "set1", "version" => 1, "categories" =>  [0 => "abc", 1 => "def"]]);
{"set":"set1","version":1,"categories":["abc","def"]}

Neboli, „abc“ a „def“ nemají index, tohle chovaní potřebuju:

echo json_encode(["set" => "set1", "version" => 1, "categories" =>  [0 => "abc", 1 => "def"]], JSON_FORCE_OBJECT);
{"set":"set1","version":1,"categories":{"0":"abc","1":"def"}}

Editoval Ajax (23. 10. 2017 18:29)

Jan Tvrdík
Nette guru | 2595
+
0
-

To co chceš je antipattern. Správně je to

echo json_encode(["set" => "set1", "version" => 1, "categories" => (object) [0 => "abc", 1 => "def"]]);
Ajax
Člen | 59
+
0
-

Hmm, chápu, tohle by to vyřešilo. Proč je to antipatern?

Jan Tvrdík
Nette guru | 2595
+
+1
-

Protože ti to znemožní mít v tom stejném JSONu pole.