Completed
Pull Request — master (#1957)
by
unknown
38:54 queued 22:06
created

export::outputJSON()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 47

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 8
nop 0
dl 0
loc 47
rs 9.1563
c 0
b 0
f 0
1
<?php
2
  namespace NRC;
3
4
  if (isset($_GET['debug'])) {
5
    opcache_reset();
6
    error_reporting(E_ALL);
7
    ini_set('display_errors', TRUE);
8
    ini_set('display_startup_errors', TRUE);
9
  }
10
  require_once(elgg_get_plugins_path() . 'missions/api/v0/api.php');
11
12
  class export {
13
14
    public static $version = 'v0.0.3';
15
    public static $help = <<<EOD
16
<!DOCTYPE html>
17
<html>
18
  <body>
19
    <H1>
20
      NRC Recommendation Provider API
21
      <sub style="font-size: 0.5em">::version::</sub>
22
    </H1>
23
    <p>
24
      This API provides the means by which recommendation services can collect
25
      GCConnex data.  A private key is required to access this service.
26
    </p>
27
    <H3>Endpoints</H3>
28
    <ul>
29
      <li>
30
        <h4>/missions/api/v0/export[/guid]</h4>
31
        <p>
32
          Used to export any entity.  If a guid is provided, only that entity
33
          is returned.
34
        </p>
35
        Examples:
36
        <ul>
37
          <li>/missions/api/v0/export</li>
38
          <li>/missions/api/v0/export/205</li>
39
          <li>/missions/api/v0/export/42922688</li>
40
          <li>/missions/api/v0/export?since=1539475200&limit=2</li>
41
        </ul>
42
      </li>
43
      <li>
44
        <h4>/missions/api/v0/user[/guid]</h4>
45
        <p>
46
          Used to export users.  If a guid is provided, only that user is
47
          returned.
48
        </p>
49
        Examples:
50
        <ul>
51
          <li>/missions/api/v0/user</li>
52
          <li>/missions/api/v0/user/205</li>
53
          <li>/missions/api/v0/user?since=1539475200</li>
54
        </ul>
55
      </li>
56
      <li>
57
        <h4>
58
          /missions/api/v0/object[/guid]<br>
59
          /missions/api/v0/object/subtype[/guid]
60
        </h4>
61
        <p>
62
          Used to export objects.  If a guid is provided, only that object is
63
          returned.  A subtype can also be specified.
64
        </p>
65
        Examples:
66
        <ul>
67
          <li>/missions/api/v0/object</li>
68
          <li>/missions/api/v0/object/42922688</li>
69
          <li>/missions/api/v0/object?since=1539475200&limit=1</li>
70
          <li>/missions/api/v0/object/widget?since=1539475200</li>
71
        </ul>
72
      </li>
73
    </ul>
74
    <H3>Query parameters</H3>
75
    <p>Parameters can be used to perform more complex queries.</p>
76
    <table>
77
      <thead>
78
        <tr>
79
          <th>Parameter</th>
80
          <th>Description</th>
81
        </tr>
82
      </thead>
83
      <tbody>
84
        <tr>
85
          <td>before</td>
86
          <td>
87
            Fetch entities that have been modified before the specified time.
88
            Expects a unix timetamp.
89
          </td>
90
        </tr>
91
        <tr>
92
          <td>since</td>
93
          <td>
94
            Fetch entities that have been modified after the specified time.
95
            Expects a unix timetamp.
96
          </td>
97
        </tr>
98
        <tr>
99
          <td>limit</td>
100
          <td>
101
            Limits the number of returned entities.  Expects an positive
102
            integer.
103
          </td>
104
        </tr>
105
        <tr>
106
          <td>resume</td>
107
          <td>
108
            Resume starting at the specified GUID.  Expects a valid GUID.
109
          </td>
110
        </tr>
111
        <tr>
112
          <td>sort</td>
113
          <td>
114
            If specified sorts returned entities by created time - By default
115
            rows are returned in natural order without any sorting guarantees.
116
            This parameter doesn't take any value, its presence enables
117
            sorting.
118
          </td>
119
        </tr>
120
        <tr>
121
          <td>omit</td>
122
          <td>
123
            List of GUIDs to omit from the results.  Useful to omit large
124
            objects we know we are not interested in.  For example GUID "1".
125
            Takes a comma separated list of GUIDs.
126
          </td>
127
        </tr>
128
        <tr>
129
          <td>count</td>
130
          <td>
131
            Include the total number of entities that match the search
132
            criteria.  (Executes a separate query on the server to count)
133
          </td>
134
        </tr>
135
        <tr>
136
          <td>version<strong>*<strong></td>
137
          <td>
138
            Returns the API version as a JSON object and exits.  No query is
139
            performed regardless of other parameters.
140
          </td>
141
        </tr>
142
        <tr>
143
          <td>help<strong>*<strong></td>
144
          <td>
145
            Returns the API help text as an HTML page and exits.  No query is
146
            performed regardless of other parameters.
147
          </td>
148
        </tr>
149
      </table>
150
      <small><strong>*<strong> These parameters do not require a private key</small>
151
      <H3>Returns</H3>
152
      Successful queries return JSON objects like this:
153
      <pre>
154
      {
155
        "query": {
156
            "object_type": "export",     // type of export
157
            "api_version": "v0.0.3",     // current API version
158
            "subtype": false,            // requested subtype, if specified
159
            "guid": null,                // requested GUID, if specified
160
            "since": "1539475200",       // "since" parameter, if specified
161
            "before": null,              // "before" parameter, if specified
162
            "limit": null,               // "limit" parameter, if specified
163
            "request_time": 1546958611,  // server's current unix timestamp
164
            "count": 14                  // Total number of matched entities
165
        },
166
        "export": [ ... ]                // Array of requested entities
167
      }
168
      </pre>
169
  </body>
170
</html>
171
EOD;
172
173
    private $object_type = false;
174
    private $subtype = false;
175
    private $guid = null;
176
    private $since = null;
177
    private $before = null;
178
    private $limit = null;
179
    private $omit = null;
180
181
    static function getHelp() {
182
      return str_replace('::version::', self::$version, self::$help);
183
    }
184
185
    function __construct($object_type, $subtype = false, $guid = null,
186
      $since = null, $before = null, $limit = null, $resume = null,
187
      $sort = false, $omit = null, $count = false) {
188
189
      mm_api_secure();
190
191
      $this->object_type = $object_type;
192
      $this->subtype = $subtype;
193
      $this->guid = $guid;
194
      $this->since = $since;
195
      $this->before = $before;
196
      $this->limit = $limit;
197
      $this->resume = $resume;
0 ignored issues
show
Bug introduced by
The property resume does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
198
      $this->sort = $sort;
0 ignored issues
show
Bug introduced by
The property sort does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
199
      $this->omit = $omit;
200
      $this->count = $count;
0 ignored issues
show
Bug introduced by
The property count does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
201
    }
202
203
    public static function getQueryCount() {
204
      $queries_result = mysql_query(
205
        'show session status like "Queries";',
206
        _elgg_services()->db->getLink('read')
207
      );
208
      $r = mysql_fetch_object($queries_result);
209
      $queries = $r->Value;
210
      mysql_free_result($queries_result);
211
      return intval($queries) - 1;
212
    }
213
214
    /**
215
     * Stream the export results using JSON format
216
     */
217
    function outputJSON() {
218
      while (@ob_end_flush());
219
220
      $queryCount = self::getQueryCount();
221
      $exporter = mm_api_export_entities(
222
        $this->object_type,
0 ignored issues
show
Documentation introduced by
$this->object_type is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
223
        $this->subtype,
0 ignored issues
show
Documentation introduced by
$this->subtype is of type boolean, but the function expects a false|string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
224
        $this->guid,
225
        $this->since,
226
        $this->before,
227
        $this->limit,
228
        $this->resume,
229
        $this->sort,
230
        $this->omit,
231
        $this->count
232
      );
233
      $queryData = [
234
        'object_type' => $this->object_type,
235
        'api_version' => self::$version,
236
        'subtype' => $this->subtype,
237
        'guid' => $this->guid,
238
        'since' => $this->since,
239
        'before' => $this->before,
240
        'limit' => $this->limit,
241
        'request_time' => time(),
242
      ];
243
      if ($this->count) {
244
        $queryData['count'] = $exporter->current();
0 ignored issues
show
Bug introduced by
The method current cannot be called on $exporter (of type array<integer,object<Generator>>|null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
245
      }
246
      echo '{"query":' .json_encode($queryData). ',"export":[';
247
      flush();
248
      $exporter->next();
0 ignored issues
show
Bug introduced by
The method next cannot be called on $exporter (of type array<integer,object<Generator>>|null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
249
250
      // ignore the first comma
251
      $exporter->next();
0 ignored issues
show
Bug introduced by
The method next cannot be called on $exporter (of type array<integer,object<Generator>>|null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
252
253
      while ($exporter->valid()) {
0 ignored issues
show
Bug introduced by
The method valid cannot be called on $exporter (of type array<integer,object<Generator>>|null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
254
        $output = $exporter->current();
0 ignored issues
show
Bug introduced by
The method current cannot be called on $exporter (of type array<integer,object<Generator>>|null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
255
        echo $output;
256
        flush();
257
        ob_flush();
258
        $exporter->next();
0 ignored issues
show
Bug introduced by
The method next cannot be called on $exporter (of type array<integer,object<Generator>>|null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
259
      }
260
      $queryCount = self::getQueryCount() - $queryCount - 2;
261
      echo "], \"queryCount\": $queryCount}\r\n";
262
      exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method outputJSON() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
263
    }
264
  }
265
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
266