Skip to content

Commit c971cd9

Browse files
committed
Merge branch 'release/v1.0.0'
2 parents 9eb54d5 + e025343 commit c971cd9

13 files changed

+930
-2
lines changed

.travis.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ matrix:
2020
include:
2121
- php: 7.1
2222
env: 'COMPOSER_FLAGS="--prefer-stable --prefer-lowest"'
23+
allow_failures:
24+
- php: hhvm
2325

2426
before_script:
2527
- travis_retry composer update ${COMPOSER_FLAGS} --no-interaction --prefer-dist

README.md

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,39 @@ $ composer require cerbero/json-objects
1919

2020
## Usage
2121

22+
Simply pass the JSON source (files, endpoints, streams) and optionally the key where objects are contained to create a
23+
new instance of `JsonObjects`. You can also call the factory method `from()`:
24+
25+
``` php
26+
$source = 'https://jsonplaceholder.typicode.com/users';
27+
28+
// Create a new instance specifying the JSON source to extract objects from
29+
new JsonObjects($source);
30+
// or
31+
JsonObjects::from($source);
32+
33+
// Create a new instance specifying the JSON source and the key to extract objects from
34+
new JsonObjects($source, 'address.geo');
35+
// or
36+
JsonObjects::from($source, 'address.geo');
37+
```
38+
39+
When providing a key to extract objects from, you can use the dot notation to indicate nested sections of a JSON. For
40+
example `nested.*.key` extracts all the objects in the property `key` of every object contained in `nested`.
41+
42+
Finally you can decide whether to extract and process objects one by one or in chunks. The memory will be allocated to
43+
read these objects only instead of the whole JSON document:
44+
2245
``` php
23-
// @todo Add usage description.
46+
// Extract and process one object at a time from the given JSON source
47+
JsonObjects::from($source)->each(function (array $object) {
48+
// Process one object
49+
});
50+
51+
// Extract and process a chunk of objects at a time from the given JSON source
52+
JsonObjects::from($source)->chunk(100, function (array $objects) {
53+
// Process 100 objects
54+
});
2455
```
2556

2657
## Change log

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
}
2121
],
2222
"require": {
23-
"php": "~7.1"
23+
"php": "~7.1",
24+
"salsify/json-streaming-parser": "^8.0"
2425
},
2526
"require-dev": {
2627
"phpunit/phpunit": ">=7.0",

src/JsonObjects.php

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
<?php
2+
3+
namespace Cerbero\JsonObjects;
4+
5+
use Exception;
6+
use JsonStreamingParser\Parser;
7+
use Cerbero\JsonObjects\Listeners\AbstractListener;
8+
use Cerbero\JsonObjects\Listeners\ChunkListener;
9+
use Cerbero\JsonObjects\Listeners\ObjectListener;
10+
11+
/**
12+
* The JSON objects main class.
13+
*
14+
*/
15+
class JsonObjects
16+
{
17+
/**
18+
* The JSON stream.
19+
*
20+
* @var resource
21+
*/
22+
protected $stream;
23+
24+
/**
25+
* The key containing the JSON objects.
26+
*
27+
* @var string|null
28+
*/
29+
protected $key;
30+
31+
/**
32+
* Set the dependencies.
33+
*
34+
* @param resource|string $source
35+
* @param string|null $key
36+
*
37+
* @throws JsonObjectsException
38+
*/
39+
public function __construct($source, string $key = null)
40+
{
41+
$this->setStreamFromSource($source);
42+
43+
$this->key = $key;
44+
}
45+
46+
/**
47+
* Set the JSON stream from the given source
48+
*
49+
* @param mixed $source
50+
* @return void
51+
*
52+
* @throws JsonObjectsException
53+
*/
54+
protected function setStreamFromSource($source) : void
55+
{
56+
if (is_resource($source)) {
57+
$this->stream = $source;
58+
return;
59+
}
60+
61+
if (!is_string($source)) {
62+
throw new JsonObjectsException('Unable to create a stream from the given source.');
63+
}
64+
65+
$this->stream = extension_loaded('zlib') ? @gzopen($source, 'rb') : @fopen($source, 'rb');
66+
67+
if ($this->stream === false) {
68+
throw new JsonObjectsException("Failed to open stream from: {$source}");
69+
}
70+
}
71+
72+
/**
73+
* Create a new instance while easing method chaining
74+
*
75+
* @param resource|string $source
76+
* @param string|null $key
77+
* @return self
78+
*
79+
* @throws JsonObjectsException
80+
*/
81+
public static function from($source, string $key = null) : self
82+
{
83+
return new static($source, $key);
84+
}
85+
86+
/**
87+
* Process each JSON object separately
88+
*
89+
* @param callable $callback
90+
* @return void
91+
*
92+
* @throws JsonObjectsException
93+
*/
94+
public function each(callable $callback) : void
95+
{
96+
$this->parseStreamWithListener(new ObjectListener($callback));
97+
}
98+
99+
/**
100+
* Parse the JSON stream with the given listener
101+
*
102+
* @param AbstractListener $listener
103+
* @return void
104+
*
105+
* @throws JsonObjectsException
106+
*/
107+
protected function parseStreamWithListener(AbstractListener $listener) : void
108+
{
109+
if ($this->key !== null) {
110+
$listener->setTargetFromKey($this->key);
111+
}
112+
113+
try {
114+
(new Parser($this->stream, $listener))->parse();
115+
} catch (Exception $e) {
116+
throw new JsonObjectsException($e->getMessage());
117+
} finally {
118+
extension_loaded('zlib') ? gzclose($this->stream) : fclose($this->stream);
119+
}
120+
}
121+
122+
/**
123+
* Process JSON objects in chunks
124+
*
125+
* @param int $size
126+
* @param callable $callback
127+
* @return void
128+
*
129+
* @throws JsonObjectsException
130+
*/
131+
public function chunk(int $size, callable $callback) : void
132+
{
133+
$this->parseStreamWithListener(new ChunkListener($size, $callback));
134+
}
135+
}

src/JsonObjectsException.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace Cerbero\JsonObjects;
4+
5+
use Exception;
6+
7+
/**
8+
* The JSON objects exception.
9+
*
10+
*/
11+
class JsonObjectsException extends Exception
12+
{
13+
//
14+
}

0 commit comments

Comments
 (0)