diff --git a/README.md b/README.md index c1cda10..98a6b0f 100755 --- a/README.md +++ b/README.md @@ -193,14 +193,14 @@ You don't need to call `fetch()` method after this. Because this method will fet Let's say you want to get the value of _'cities'_ property of your Json Data. You can do it like this: ```php -$q = new jsonq('data.json'); +$q = new Jsonq('data.json'); echo $q->find('vendor.name'); ``` If you want to traverse to more deep in hierarchy, you can do it like: ```php -$q = new jsonq('data.json'); +$q = new Jsonq('data.json'); echo $q->find('vendor.name'); ``` @@ -219,14 +219,14 @@ Difference between this method and `find()` is that, `find()` method will return Let's say you want to start query over the values of _'vendor.name'_ property of your JSON Data. You can do it like this: ```php -$q = new jsonq('data.json'); +$q = new Jsonq('data.json'); echo $q->from('vendor.name')->get(); ``` If you want to traverse to more deep in hierarchy, you can do it like: ```php -$q = new jsonq('data.json'); +$q = new Jsonq('data.json'); echo $q->from('users.5.visits')->get(); ``` @@ -273,14 +273,14 @@ This is an alias method of `from()` and will behave exactly like that. See examp Let's say you want to find the _'users'_ who has _`id`_ of `1`. You can do it like this: ```php -$q = new jsonq('data.json'); +$q = new Jsonq('data.json'); $res = $q->from('users')->where('id', '=', 1)->get(); ``` You can add multiple _where_ conditions. It'll give the result by AND-ing between these multiple where conditions. ```php -$q = new jsonq('data.json'); +$q = new Jsonq('data.json'); $res = $q->from('users') ->where('id', '=', 1) ->where('location', '=', 'barisal') @@ -296,7 +296,7 @@ Parameters of `orWhere()` are the same as `where()`. The only difference between For example, if you want to find the users with _id_ of `1` or `2`, you can do it like this: ```php -$q = new jsonq('data.json'); +$q = new Jsonq('data.json'); $res = $q->from('users') ->where('id', '=', 1) ->orWhere('id', '=', 2) @@ -361,7 +361,7 @@ This method will behave like `where(key, 'contains', val)` method call. Let's say you want to find the sum of the _'price'_ of the _'products'_. You can do it like this: ```php -$q = new jsonq('data.json'); +$q = new Jsonq('data.json'); $res = $q->from('products') ->where('cat', '=', 1) ->sum('price'); @@ -379,7 +379,7 @@ It will return the number of elements in the collection. Let's say you want to find how many elements are in the _'products'_ property. You can do it like: ```php -$q = new jsonq('data.json'); +$q = new Jsonq('data.json'); $res = $q->from('products') ->where('cat', '=', 1) ->count(); @@ -400,7 +400,7 @@ This is an alias method of `count()`. Let's say you want to find the maximum of the _'price'_ of the _'products'_. You can do it like this: ```php -$q = new jsonq('data.json'); +$q = new Jsonq('data.json'); $res = $q->from('products') ->where('cat', '=', 1) ->max('price); @@ -418,7 +418,7 @@ See detail example [here](examples/max.php) Let's say you want to find the minimum of the _'price'_ of the _'products'_. You can do it like this: ```php -$q = new jsonq('data.json'); +$q = new Jsonq('data.json'); $res = $q->from('products') ->where('cat', '=', 1) ->min('price'); @@ -436,7 +436,7 @@ See detail example [here](examples/min.php) Let's say you want to find the average of the _'price'_ of the _'products'_. You can do it like this: ```php -$q = new jsonq('data.json'); +$q = new Jsonq('data.json'); $res = $q->from('products') ->where('cat', '=', 1) ->avg('price'); @@ -467,7 +467,7 @@ It will return the last element of the collection. **example:** ```php -$q = new jsonq('data.json'); +$q = new Jsonq('data.json'); $res = $q->from('products') ->where('cat', '=', 1) ->last(); @@ -484,7 +484,7 @@ It will return the nth element of the collection. If the given index is a **posi **example:** ```php -$q = new jsonq('data.json'); +$q = new Jsonq('data.json'); $res = $q->from('products') ->where('cat', '=', 1) ->nth(2); @@ -501,7 +501,7 @@ It will return **true** if the element is not **empty** or not **null** or not a Let's say you want to find how many elements are in the _'products'_ property. You can do it like: ```php -$q = new jsonq('data.json'); +$q = new Jsonq('data.json'); $res = $q->from('products') ->where('cat', '=', 1) ->exists(); @@ -518,7 +518,7 @@ See detail example [here](examples/exists.php). Let's say you want to group the _'users'_ data based on the _'location'_ property. You can do it like: ```php -$q = new jsonq('data.json'); +$q = new Jsonq('data.json'); $res = $q->from('users') ->groupBy('location') ->get(); @@ -537,8 +537,8 @@ See detail example [here](examples/group-by.php). Let's say you want to sort the _'arr'_ data. You can do it like: ```php -$q = new jsonq(); -$res = $q->collect([7, 5, 9, 1, 3) +$q = new Jsonq(); +$res = $q->collect([7, 5, 9, 1, 3]) ->sort(); ``` @@ -556,7 +556,7 @@ See detail example [here](examples/sort.php). Let's say you want to sort the _'price'_ data of _'products'_. You can do it like: ```php -$q = new jsonq('data.json'); +$q = new Jsonq('data.json'); $res = $q->from('products') ->where('cat', '=', 1) ->sortBy('price', 'desc'); diff --git a/src/JsonQueriable.php b/src/JsonQueriable.php index d130d17..ffc308e 100644 --- a/src/JsonQueriable.php +++ b/src/JsonQueriable.php @@ -4,6 +4,7 @@ use Nahid\JsonQ\Exceptions\ConditionNotAllowedException; use Nahid\JsonQ\Exceptions\FileNotFoundException; +use Nahid\JsonQ\Exceptions\InvalidJsonException; trait JsonQueriable { @@ -76,15 +77,15 @@ trait JsonQueriable /** * import data from file * - * @param $json_file string + * @param string $file * @return bool * @throws FileNotFoundException */ - public function import($json_file = null) + public function import($file = null) { - if (!is_null($json_file)) { - if (file_exists($json_file)) { - $this->_map = $this->getDataFromFile($json_file); + if (!is_null($file)) { + if (is_string($file) && file_exists($file)) { + $this->_map = $this->getDataFromFile($file); $this->_baseContents = $this->_map; return true; } @@ -121,9 +122,9 @@ protected function prepare() } /** - * parse object to array + * Parse object to array * - * @param $obj object + * @param object $obj * @return array|mixed */ protected function objectToArray($obj) @@ -144,9 +145,9 @@ protected function objectToArray($obj) } /** - * check given value is multidimensional array + * Check given value is multidimensional array * - * @param $arr array + * @param array $arr * @return bool */ protected function isMultiArray($arr) @@ -161,16 +162,26 @@ protected function isMultiArray($arr) } /** - * check given value is valid JSON - * @param $value string - * @param $return_map bool - * @return bool|array|string + * Check given value is valid JSON + * + * @param string $value + * @param bool $isReturnMap + * + * @return bool|array */ - public function isJson($value, $return_map = false) + public function isJson($value, $isReturnMap = false) { + if (is_array($value) || is_object($value)) { + return false; + } + $data = json_decode($value, true); - return (json_last_error() == JSON_ERROR_NONE) ? ($return_map ? $data : true) : json_last_error_msg(); + if (json_last_error() !== JSON_ERROR_NONE) { + return false; + } + + return $isReturnMap ? $data : true; } /** @@ -212,10 +223,14 @@ protected function getDataFromFile($file, $type = 'application/json') ]; $context = stream_context_create($opts); - $data = file_get_contents($file, 0, $context); - - return $this->isJson($data, true); + $json = $this->isJson($data, true); + + if (!$json) { + throw new InvalidJsonException(); + } + + return $json; } throw new FileNotFoundException(); diff --git a/src/Jsonq.php b/src/Jsonq.php index 0b38b2e..c3c0f76 100644 --- a/src/Jsonq.php +++ b/src/Jsonq.php @@ -523,10 +523,10 @@ public function then($node) */ public function json($data) { - if (is_string($data)) { - if ($json = $this->isJson($data, true)) { - return $this->collect($json); - } + $json = $this->isJson($data, true); + + if ($json) { + return $this->collect($json); } return $this; diff --git a/tests/AbstractTestCase.php b/tests/AbstractTestCase.php new file mode 100644 index 0000000..f9f3f65 --- /dev/null +++ b/tests/AbstractTestCase.php @@ -0,0 +1,21 @@ +setAccessible(true); + + return $method; + } +} diff --git a/tests/JsonQueriableTest.php b/tests/JsonQueriableTest.php new file mode 100644 index 0000000..7d5df9f --- /dev/null +++ b/tests/JsonQueriableTest.php @@ -0,0 +1,198 @@ + [ + 'level2.1' => [ + 'level3.1' => 'data31', + 'level3.2' => 32, + 'level3.3' => true, + ], + 'level2.2' => [ + 'level3.4' => 'data34', + 'level3.5' => 35, + 'level3.6' => false, + ], + 'level2.3' => [ + 'level3.7' => 'data37', + 'level3.8' => 38, + 'level3.9' => true, + ] + ], + 'level1.2' => [ + 'level2.4' => [ + 'level3.10' => 'data310', + 'level3.11' => 311, + 'level3.12' => true, + ], + 'level2.5' => [ + 'level3.13' => 'data313', + 'level3.14' => 314, + 'level3.15' => false, + ], + 'level2.6' => [ + 'level3.16' => 'data316', + 'level3.17' => 317, + 'level3.18' => true, + ] + ] + ]; + + file_put_contents(self::FILE_NAME, json_encode($json)); + $this->file = self::FILE_NAME; + } + + protected function removeFile() + { + unlink(self::FILE_NAME); + $this->file = null; + } + + /** + * @return \StdClass + */ + private function getTestObject() + { + $object = new \stdClass(); + $object->testField = 'test'; + $object->test_field2 = 'test2'; + $object->testfield3 = 'test3'; + + return $object; + } + + protected function setUp() + { + $this->createFile(); + $this->jsonq = new Jsonq(self::FILE_NAME); + } + + protected function tearDown() + { + $this->removeFile(); + } + + /** + * @param mixed $file + * @param bool $result + * + * @dataProvider importProvider + */ + public function testImport($file, $result) + { + if ($result) { + $this->assertEquals(true, $this->jsonq->import($file)); + } else { + $this->expectException(FileNotFoundException::class); + $this->jsonq->import($file); + } + } + + /** + * @param mixed $input + * @param mixed $result + * + * @dataProvider objectToArrayProvider + */ + public function testObjectToArray($input, $result) + { + $method = $this->makeCallable($this->jsonq, 'objectToArray'); + + $this->assertEquals($result, $method->invokeArgs($this->jsonq, [$input])); + } + + /** + * @param mixed $input + * @param bool $result + * + * @dataProvider isMultiArrayProvider + */ + public function testIsMultiArray($input, $result) + { + $method = $this->makeCallable($this->jsonq, 'isMultiArray'); + + $this->assertEquals($result, $method->invokeArgs($this->jsonq, [$input])); + } + + /** + * @param mixed $input + * @param bool $isReturnMap + * @param mixed $result + * + * @dataProvider isJsonProvider + */ + public function testIsJson($input, $isReturnMap, $result = null) + { + $this->assertEquals($result, $this->jsonq->isJson($input, $isReturnMap)); + } + + public function isJsonProvider() + { + return [ + [null, false, false], + [true, false, true], + [1, false, true], + [new \StdClass(), false, false], + [['test'], false, false], + ['invalid_json_string', false, false], + [json_encode('valid_json_string'), false, true], + [json_encode('valid_json_string'), true, 'valid_json_string'] + ]; + } + + public function isMultiArrayProvider() + { + return [ + [null, false], + [true, false], + [1, false], + ['test', false], + [['test', 'test'], false], + [['test',['test']], true], + [[['test'], 'test'], true] + ]; + } + + public function importProvider() + { + return [ + [self::FILE_NAME, true], + [null, false], + [true, false], + [1, false], + ['invalid_path.json', false] + ]; + } + + public function objectToArrayProvider() + { + return [ + [null, null], + [true, true], + [1, 1], + ['test', 'test'], + [['data1', 'data2'],['data1', 'data2']], + [$this->getTestObject(), ['testField' => 'test', 'test_field2' => 'test2', 'testfield3' => 'test3']] + ]; + } +}