Completed
Push — develop ( 18ee8c...489265 )
by Patrick
09:31 queued 06:48
created

FlipRESTFormat::create_excel()   C

Complexity

Conditions 12
Paths 4

Size

Total Lines 61
Code Lines 37

Duplication

Lines 23
Ratio 37.7 %

Importance

Changes 0
Metric Value
cc 12
eloc 37
nc 4
nop 1
dl 23
loc 61
rs 6.2855
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
require_once('class.FlipSession.php');
3
require_once('libs/Slim/Slim/Slim.php');
4
require_once('Autoload.php');
5
\Slim\Slim::registerAutoloader();
6
7
const SUCCESS = 0;
8
const UNRECOGNIZED_METHOD = 1;
9
const INVALID_PARAM = 2;
10
const ALREADY_LOGGED_IN = 3;
11
const INVALID_LOGIN = 4;
12
const ACCESS_DENIED = 5;
13
const INTERNAL_ERROR = 6;
14
15
const UNKNOWN_ERROR = 255;
16
17
class OAuth2Auth extends \Slim\Middleware
18
{
19
    protected $headers = array();
20
21
    public function __construct($headers)
22
    {
23
        $this->headers = array_change_key_case($headers);
24
    }
25
26
    private function getUserFromSession()
27
    {
28
        if(FlipSession::isLoggedIn())
29
        {
30
            return FlipSession::getUser();
31
        }
32
        return false;
33
    }
34
35
    /*
36
     * @SuppressWarnings("Superglobals")
37
     * @SuppressWarnings("StaticAccess")
38
     */
39
    private function getUserFromBasicAuth($header)
40
    {
41
        $auth = \AuthProvider::getInstance();
42
        $auth->login($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
43
        $user = FlipSession::getUser();
44
        if($user === false)
45
        {
46
            $data = substr($header, 6);
47
            $userpass = explode(':', base64_decode($data));
48
            $user = $auth->getUserByLogin($userpass[0], $userpass[1]);
49
        }
50
        return $user;
51
    }
52
53
    /*
54
     * @SuppressWarnings("StaticAccess")
55
     */
56
    private function getUserFromToken($header)
57
    {
58
        $auth = \AuthProvider::getInstance();
59
        $key = substr($header, 7);
60
        return $auth->getUserByAccessCode($key);
61
    }
62
63
    private function getUserFromHeader($header)
64
    {
65
        if(strncmp($header, 'Basic', 5) == 0)
66
        {
67
            return $this->getUserFromBasicAuth($header);
68
        }
69
        return $this->getUserFromToken($header);
70
    }
71
72
    public function call()
73
    {
74
        // no auth header
75
        if(!isset($this->headers['Authorization']))
76
        {
77
            $this->app->user = $this->getUserFromSession();
78
        }
79
        else
80
        {
81
            $header = $this->headers['Authorization'];
82
            $this->app->user = $this->getUserFromHeader($header);
83
        }
84
85
        if($this->app->user === false)
86
        {
87
            $this->app->getLog()->error("No user found for call");
88
        }
89
90
        // this line is required for the application to proceed
91
        $this->next->call();
92
    }
93
}
94
95
class FlipRESTFormat extends \Slim\Middleware
96
{
97
    private function fix_encoded_element($key, $value, &$array, $prefix = '')
98
    {
99
        if(is_array($value))
100
        {
101
            $array[$key] = implode(';', $value);
102
        }
103
        else if($key === '_id' && is_object($value))
104
        {
105
            $array[$key] = $value->{'$id'};
106
        }
107
        else if(is_object($value))
108
        {
109
            $array[$key] = $this->app->request->getUrl().$this->app->request->getPath().$prefix.'/'.$key;
110
        }
111
        else if(strncmp($value, 'data:', 5) === 0)
112
        {
113
            $array[$key] = $this->app->request->getUrl().$this->app->request->getPath().$prefix.'/'.$key;
114
        }
115
    }
116
117
    private function createCSV(&$array)
118
    {
119
        if(count($array) == 0)
120
        {
121
            return null;
122
        }
123
        ob_start();
124
        $df = fopen("php://output", 'w');
125
        if(is_array($array))
126
        {
127
            $first = reset($array);
128
            $keys = FALSE;
129 View Code Duplication
            if(is_array($first))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
130
            {
131
                $keys = array_keys($first);
132
            }
133
            else if(is_object($first))
134
            {
135
                $keys = array_keys(get_object_vars($first));
136
            }
137
            fputcsv($df, $keys);
138
            foreach($array as $row)
139
            {
140
                if(is_array($row))
141
                {
142
                    $id = $row[$keys[0]];
143
                    foreach($row as $key=>$value)
144
                    {
145
                        $this->fix_encoded_element($key, $value, $row, '/'.$id);
146
                    }
147
                    fputcsv($df, $row);
148
                }
149
                else if(is_object($row))
150
                {
151
                    $keyName = $keys[0];
152
                    $id = $row->$keyName;
153
                    if(is_object($id))
154
                    {
155
                        $id = $id->{'$id'};
156
                    }
157
                    $values = get_object_vars($row);
158
                    foreach($values as $key=>$value)
159
                    {
160
                        $this->fix_encoded_element($key, $value, $values, '/'.$id);
161
                    }
162
                    fputcsv($df, $values);
163
                }
164
            }
165
        }
166
        else
167
        {
168
            $array = get_object_vars($array);
169
            fputcsv($df, array_keys($array));
170
            foreach($array as $key=>$value)
171
            {
172
                $this->fix_encoded_element($key, $value, $array);
173
            }
174
            fputcsv($df, $array);
175
        }
176
        fclose($df);
177
        return ob_get_clean();
178
    }
179
180
    private function collapseEntityToArray($entity, &$array, $keyPrefix='')
181
    {
182
        if(array_keys($entity) === range(0, count($entity) - 1))
183
        {
184
            $tmpCount = count($entity);
185 View Code Duplication
            for($i = 0; $i < $tmpCount; $i++)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
186
            {
187
                $tmpKey = $keyPrefix.'['.$i.']';
188
                if(is_object($entity[$i]) || is_array($entity[$i]))
189
                {
190
                    $this->collapseEntityToArray($entity[$i], $array, $tmpKey);
191
                }
192
                else
193
                {
194
                    $array[$tmpKey] = $entity[$i];
195
                }
196
            }
197
            return;
198
        }
199
200
        foreach($entity as $key=>$data)
201
        {
202
            if(is_object($data))
203
            {
204
               $data = get_object_vars($data);
205
            }
206
207
            if(is_array($data))
208
            {
209
                if(array_keys($data) !== range(0, count($data) - 1))
210
                {
211
                    //Key array
212
                    foreach($data as $childKey=>$childData)
213
                    {
214
                        $tmpKey = $keyPrefix.$key.'.'.$childKey;
215
                        if(is_object($childData) || is_array($childData))
216
                        {
217
                            $this->collapseEntityToArray($childData, $array, $tmpKey);
218
                        }
219
                        else
220
                        {
221
                            $array[$tmpKey] = $childData;
222
                        }
223
                    }
224
                }
225
                else
226
                {
227
                    //Numeric array
228
                    $tmpCount = count($data);
229 View Code Duplication
                    for($j = 0; $j < $tmpCount; $j++)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
230
                    {
231
                        $tmpKey = $keyPrefix.$key.'['.$j.']';
232
                        if(is_object($data[$j]) || is_array($data[$j]))
233
                        {
234
                            $this->collapseEntityToArray($data[$j], $array, $tmpKey);
235
                        }
236
                        else
237
                        {
238
                            $array[$tmpKey] = $data[$j];
239
                        }
240
                    }
241
                }
242
            }
243
            else
244
            {
245
                $array[$keyPrefix.$key] = $data;
246
            }
247
        }
248
    }
249
250
    private function createCSV2(&$array)
251
    {
252
        if(count($array) == 0)
253
        {
254
            return null;
255
        }
256
        if(is_object($array))
257
        {
258
            $array = get_object_vars($array);
259
        }
260
        $rowCount = count($array);
261
        $keys = array();
262
        for($i = 0; $i < $rowCount; $i++)
263
        {
264
            $row = $array[$i];
265
            if(is_object($row))
266
            {
267
                $row = get_object_vars($row);
268
                $array[$i] = $row;
269
            }
270
            if(isset($row['_empty_']))
271
            {
272
                unset($row['_empty_']);
273
                $array[$i] = $row;
274
            }
275
            if(isset($row['_id']))
276
            {
277
                $row['_id'] = $row['_id']->{'$id'};
278
                $array[$i] = $row;
279
            }
280
            $newRow = array();
281
            $this->collapseEntityToArray($row, $newRow);
282
            $row = $newRow;
283
            $array[$i] = $row;
284
            $keys = array_merge($keys, $row);
285
        }
286
        $keys = array_keys($keys);
287
        asort($keys);
288
        ob_start();
289
        $df = fopen("php://output", 'w');
290
        fputcsv($df, $keys);
291
        for($i = 0; $i < $rowCount; $i++)
292
        {
293
            $tmp = array_fill_keys($keys, '');
294
            $row = $array[$i];
295
            $tmp = array_merge($tmp, $row);
296
            ksort($tmp);
297
            fputcsv($df, $tmp);
298
        }
299
        fclose($df);
300
        return ob_get_clean();
301
    }
302
303
    private function create_excel(&$array)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
304
    {
305
        require_once dirname(__FILE__).'/libs/PHPExcel/Classes/PHPExcel.php';
306
        $ssheat = new PHPExcel();
307
        $sheat = $ssheat->setActiveSheetIndex(0);
308
        if(is_array($array))
309
        {
310
            $first = reset($array);
311
            $keys = false;
312 View Code Duplication
            if(is_array($first))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
313
            {
314
                $keys = array_keys($first);
315
            }
316
            else if(is_object($first))
317
            {
318
                $keys = array_keys(get_object_vars($first));
319
            }
320
            $col_count = count($keys);
321
            for($i = 0; $i < $col_count; $i++)
322
            {
323
                $sheat->setCellValueByColumnAndRow($i, 1, $keys[$i]);
324
            }
325
            $row_count = count($array);
326
            for($i = 0; $i < $row_count; $i++)
327
            {
328
                $row = $array[$i];
329
                if(is_object($row))
330
                {
331
                    $row = get_object_vars($row);
332
                }
333
                for($j = 0; $j < $col_count; $j++)
334
                {
335
                    $colName = $keys[$j];
336
                    if(isset($row[$colName]))
337
                    {
338
                        $value = $row[$colName];
339 View Code Duplication
                        if(is_object($value))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
340
                        {
341
                            switch($colName)
342
                            {
343
                                case '_id':
344
                                    $value = $value->{'$id'};
345
                                default:
346
                                    $value = json_encode($value);
347
                                    break;
348
                            }
349
                        }
350
                        else if(is_array($value))
351
                        {
352
                            $value = implode(',', $value);
353
                        }
354
                        $sheat->setCellValueByColumnAndRow($j, 2 + $i, $value);
355
                    }
356
                }
357
            }
358
        }
359
        $writer = PHPExcel_IOFactory::createWriter($ssheat, 'Excel2007');
360
        ob_start();
361
        $writer->save('php://output');
362
        return ob_get_clean();
363
    }
364
365
    private function createXML(&$array)
366
    {
367
        $obj = new SerializableObject($array);
368
        return $obj->xmlSerialize();
369
    }
370
371
    private function serializeData()
372
    {
373
        $data = json_decode($this->app->response->getBody());
374
        switch($this->app->fmt)
375
        {
376
            case 'data-table':
377
                $this->app->response->headers->set('Content-Type', 'application/json');
378
                return json_encode(array('data'=>$data));
379 View Code Duplication
            case 'csv':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
380
                $this->app->response->headers->set('Content-Type', 'text/csv');
381
                $path = $this->app->request->getPathInfo();
382
                $path = strrchr($path, '/');
383
                $path = substr($path, 1);
384
                $this->app->response->headers->set('Content-Disposition', 'attachment; filename='.$path.'.csv');
385
                return $this->createCSV($data);
386 View Code Duplication
            case 'csv2':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
387
                $this->app->response->headers->set('Content-Type', 'text/csv');
388
                $path = $this->app->request->getPathInfo();
389
                $path = strrchr($path, '/');
390
                $path = substr($path, 1);
391
                $this->app->response->headers->set('Content-Disposition', 'attachment; filename='.$path.'.csv');
392
                return $this->createCSV2($data);
393
            case 'xml':
394
                $this->app->response->headers->set('Content-Type', 'application/xml');
395
                return $this->createXML($data);
396
            case 'passthru':
397
                return $this->app->response->getBody();
398
            default:
399
                return 'Unknown fmt '.$this->app->fmt;
400
        }
401
    }
402
403
    private function getFormatFromHeader()
404
    {
405
        $mimeType = $this->app->request->headers->get('Accept');
406
        if(strstr($mimeType, 'odata.streaming=true'))
407
        {
408
            $this->app->response->setStatus(406);
409
            return 'json';
410
        }
411
        switch($mimeType)
412
        {
413
            case 'text/csv':
414
                return 'csv';
415
            case 'text/x-vCard':
416
                return 'vcard';
417
            default:
418
                return 'json';
419
        }
420
    }
421
422
    private function getFormat($params)
423
    {
424
        $fmt = null;
425
        if(isset($params['fmt']))
426
        {
427
            $fmt = $params['fmt'];
428
        }
429
        if($fmt === null && isset($params['$format']))
430
        {
431
            $fmt = $params['$format'];
432
            if(strstr($fmt, 'odata.streaming=true'))
433
            {
434
                $this->app->response->setStatus(406);
435
                return false;
436
            }
437
        }
438
        if($fmt === null)
439
        {
440
            $fmt = $this->getFormatFromHeader();
441
        }
442
        return $fmt;
443
    }
444
445
    public function call()
446
    {
447
        if($this->app->request->isOptions())
448
        {
449
            return;
450
        }
451
        $params = $this->app->request->params();
452
        $fmt = $this->getFormat($params);
453
        if($fmt === false)
454
        {
455
            return;
456
        }
457
458
        $this->app->fmt     = $fmt;
459
        $this->app->odata   = new ODataParams($params);
460
461
        $this->app->isLocal = false;
462
        if($_SERVER['SERVER_ADDR'] === $_SERVER['REMOTE_ADDR'])
463
        {
464
            $this->app->isLocal = true;
465
        }
466
467
        $this->next->call();
468
469
        if($this->app->response->getStatus() == 200 && $this->app->fmt !== 'json')
470
        {
471
            $text = $this->serializeData();
472
            $this->app->response->setBody($text);
473
        }
474
        else if($this->app->response->getStatus() == 200)
475
        {
476
            $this->app->response->headers->set('Content-Type', 'application/json;odata.metadata=none');
477
        }
478
    }
479
}
480
481
class FlipREST extends \Slim\Slim
482
{
483
    public function __construct()
484
    {
485
        parent::__construct();
486
        $this->config('debug', false);
487
        $headers = array();
488
        if(php_sapi_name() !== "cli")
489
        {
490
            $headers = apache_request_headers();
491
        }
492
        $this->add(new OAuth2Auth($headers));
493
        $this->add(new FlipRESTFormat());
494
        $errorHandler = array($this, 'errorHandler');
495
        $this->error($errorHandler);
496
    }
497
498
    public function get_json_body($array = false)
499
    {
500
        return $this->getJsonBody($array);
501
    }
502
503
    public function getJsonBody($array = false)
504
    {
505
        $body = $this->request->getBody();
506
        return json_decode($body, $array);
507
    }
508
509
    public function errorHandler($exception)
510
    {
511
        $error = array(
512
            'code' => $exception->getCode(),
513
            'message' => $exception->getMessage(),
514
            'file' => $exception->getFile(),
515
            'line' => $exception->getLine(),
516
        );
517
        $this->response->headers->set('Content-Type', 'application/json');
518
        error_log(print_r($error, true));
519
        echo json_encode($error);
520
    }
521
522
    function not_found_handler()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
523
    {
524
        $accept = $this->request->headers->get('Accept');
525
        if(strcmp($accept, 'application/json') == 0)
526
        {
527
            $error = array(
528
                'code' => 404,
529
                'message' => 'Not Found'
530
            );
531
            $this->response->headers->set('Content-Type', 'application/json');
532
            $this->response->setStatus(404);
533
            echo json_encode($error);
534
        }
535
        else
536
        {
537
            $this->defaultNotFound();
538
        }
539
    }
540
}
541
/* vim: set tabstop=4 shiftwidth=4 expandtab: */
542