THRIFT-2712 PHP: add "json" option to create JsonSerializable code
This patch adds a "json" option to PHP code generation that will
make generated classes implement JsonSerializable, so thrift
objects may be converted to json using json_encode() easily.
If the "validate" option is enabled, the object's write validator
will be called, beyond that the jsonSerialize() method only outputs
non-null fields in the JSON object (JSON parsers get grumpy if you
send them null where they expect to see a number).
Patch: Stig Bakken
Github Pull Request: This closes #219
diff --git a/lib/php/test/Makefile.am b/lib/php/test/Makefile.am
index a529d8c..869c544 100755
--- a/lib/php/test/Makefile.am
+++ b/lib/php/test/Makefile.am
@@ -24,25 +24,34 @@
$(THRIFT) --gen php -r --out ./packages ../../../test/ThriftTest.thrift
mkdir -p ./packages/phpv
mkdir -p ./packages/phpvo
- $(THRIFT) --gen php:validate -r --out ./packages/phpv TestValidators.thrift
- $(THRIFT) --gen php:validate,oop -r --out ./packages/phpvo TestValidators.thrift
-
+ mkdir -p ./packages/phpjs
+ $(THRIFT) --gen php:validate -r --out ./packages/phpv TestValidators.thrift
+ $(THRIFT) --gen php:validate,oop -r --out ./packages/phpvo TestValidators.thrift
+ $(THRIFT) --gen php:json -r --out ./packages/phpjs TestValidators.thrift
+
+check-json-serializer: stubs
+if HAVE_PHPUNIT
+ $(PHPUNIT) --log-junit=TEST-json-serializer.xml Test/Thrift/JsonSerialize/
+endif
+
check-validator: stubs
php Test/Thrift/TestValidators.php
php Test/Thrift/TestValidators.php -oop
check-protocol: stubs
if HAVE_PHPUNIT
- $(PHPUNIT) --log-junit=phpunit.xml Test/Thrift/Protocol/TestTJSONProtocol.php
- $(PHPUNIT) --log-junit=phpunit.xml Test/Thrift/Protocol/TestBinarySerializer.php
+ $(PHPUNIT) --log-junit=TEST-log-json-protocol.xml Test/Thrift/Protocol/TestTJSONProtocol.php
+ $(PHPUNIT) --log-junit=TEST-binary-serializer.xml Test/Thrift/Protocol/TestBinarySerializer.php
endif
-
+
check: stubs \
check-protocol \
- check-validator
+ check-validator \
+ check-json-serializer
clean-local:
$(RM) -r ./packages
+ $(RM) TEST-*.xml
EXTRA_DIST = Test
diff --git a/lib/php/test/Test/Thrift/JsonSerialize/JsonSerializeTest.php b/lib/php/test/Test/Thrift/JsonSerialize/JsonSerializeTest.php
new file mode 100644
index 0000000..7e324f0
--- /dev/null
+++ b/lib/php/test/Test/Thrift/JsonSerialize/JsonSerializeTest.php
@@ -0,0 +1,92 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+namespace Test\Thrift\JsonSerialize;
+
+use stdClass;
+use Test\Thrift\Fixtures;
+use Thrift\ClassLoader\ThriftClassLoader;
+use Thrift\Serializer\TBinarySerializer;
+
+require_once __DIR__.'/../../../../lib/Thrift/ClassLoader/ThriftClassLoader.php';
+
+$loader = new ThriftClassLoader();
+$loader->registerNamespace('Thrift', __DIR__ . '/../../../../lib');
+$loader->registerNamespace('Test', __DIR__ . '/../../..');
+$loader->registerDefinition('ThriftTest', __DIR__ . '/../../../packages/phpjs');
+$loader->register();
+
+class JsonSerializeTest extends \PHPUnit_Framework_TestCase
+{
+
+ public function testEmptyStruct() {
+ $empty = new \ThriftTest\EmptyStruct(array('non_existing_key' => 'bar'));
+ $this->assertEquals(new stdClass, json_decode(json_encode($empty)));
+ }
+
+ public function testStringsAndInts() {
+ $input = array(
+ 'string_thing' => 'foo',
+ 'i64_thing' => 1234567890,
+ );
+ $xtruct = new \ThriftTest\Xtruct($input);
+
+ // Xtruct's 'i32_thing' and 'byte_thing' fields should not be present here!
+ $expected = new stdClass;
+ $expected->string_thing = $input['string_thing'];
+ $expected->i64_thing = $input['i64_thing'];
+ $this->assertEquals($expected, json_decode(json_encode($xtruct)));
+ }
+
+ public function testNestedStructs() {
+ $xtruct2 = new \ThriftTest\Xtruct2(array(
+ 'byte_thing' => 42,
+ 'struct_thing' => new \ThriftTest\Xtruct(array(
+ 'i32_thing' => 123456,
+ )),
+ ));
+
+ $expected = new stdClass;
+ $expected->byte_thing = $xtruct2->byte_thing;
+ $expected->struct_thing = new stdClass;
+ $expected->struct_thing->i32_thing = $xtruct2->struct_thing->i32_thing;
+ $this->assertEquals($expected, json_decode(json_encode($xtruct2)));
+ }
+
+ public function testInsanity() {
+ $xinput = array('string_thing' => 'foo');
+ $xtruct = new \ThriftTest\Xtruct($xinput);
+ $insanity = new \ThriftTest\Insanity(array(
+ 'xtructs' => array($xtruct, $xtruct, $xtruct)
+ ));
+ $expected = new stdClass;
+ $expected->xtructs = array((object)$xinput, (object)$xinput, (object)$xinput);
+ $this->assertEquals($expected, json_decode(json_encode($insanity)));
+ }
+
+ public function testNestedLists() {
+ $bonk = new \ThriftTest\Bonk(array('message' => 'foo'));
+ $nested = new \ThriftTest\NestedListsBonk(array('bonk' => array(array(array($bonk)))));
+ $expected = new stdClass;
+ $expected->bonk = array(array(array((object)array('message' => 'foo'))));
+ $this->assertEquals($expected, json_decode(json_encode($nested)));
+ }
+
+}