Passed
Push — master ( 105f03...ccc732 )
by Sam
04:11
created

YamlResponseParser::parseResponse()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 5.2

Importance

Changes 0
Metric Value
eloc 11
dl 0
loc 21
ccs 8
cts 10
cp 0.8
rs 9.6111
c 0
b 0
f 0
cc 5
nc 4
nop 2
crap 5.2
1
<?php
2
3
namespace Pheanstalk;
4
5
use Pheanstalk\Contract\ResponseInterface;
6
use Pheanstalk\Contract\ResponseParserInterface;
7
use Pheanstalk\Response;
8
use Pheanstalk\Response\ArrayResponse;
9
10
/**
11
 * A response parser for commands that return a subset of YAML.
12
 *
13
 * Expected response is 'OK', 'NOT_FOUND' response is also handled.
14
 * Parser expects either a YAML list or dictionary, depending on mode.
15
 *
16
 * @author  Paul Annesley
17
 * @package Pheanstalk
18
 * @license http://www.opensource.org/licenses/mit-license.php
19
 */
20
class YamlResponseParser implements ResponseParserInterface
21
{
22
    const MODE_LIST = 'list';
23
    const MODE_DICT = 'dict';
24
25
    private $mode;
26
27
    /**
28
     * @param string $mode self::MODE_*
29
     */
30 29
    public function __construct(string $mode)
31
    {
32 29
        if (!in_array($mode, [self::MODE_DICT, self::MODE_LIST])) {
33
            throw new \InvalidArgumentException('Invalid mode');
34
        }
35 29
        $this->mode = $mode;
36
    }
37
38 29
    public function parseResponse(string $responseLine, ?string $responseData): ArrayResponse
39
    {
40 29
        if ($responseLine == ResponseInterface::RESPONSE_NOT_FOUND) {
41 1
            throw new Exception\ServerException(sprintf(
42 1
                'Server reported %s',
43
                $responseLine
44
            ));
45
        }
46
47 28
        if (!preg_match('#^OK \d+$#', $responseLine)) {
48
            throw new Exception\ServerException(sprintf(
49
                'Unhandled response: "%s"',
50
                $responseLine
51
            ));
52
        }
53
54
        $lines = array_filter(explode("\n", $responseData), function($line) {
0 ignored issues
show
Coding Style introduced by Sam Mousa
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
55 28
            return !empty($line) && $line !== '---';
56 28
        });
57
58 28
        return $this->mode === self::MODE_LIST ? $this->parseList($lines) : $this->parseDictionary($lines);
59
    }
60
61 23
    private function parseList(array $lines): ArrayResponse
62
    {
63 23
        $data = [];
64 23
        foreach($lines as $line) {
0 ignored issues
show
Coding Style introduced by Sam Mousa
Expected 1 space after FOREACH keyword; 0 found
Loading history...
65 23
            if (strncmp($line, '- ', 2) !== 0) {
66
                throw new Exception("YAML parse error for line: $line" . print_r($lines, true));
67
            }
68 23
            $data[] = substr($line, 2);
69
        }
70
71 23
        return new ArrayResponse('OK', $data);
72
    }
73 11
    private function parseDictionary(array $lines): ArrayResponse
74
    {
75 11
        $data = [];
76 11
        foreach($lines as $line) {
0 ignored issues
show
Coding Style introduced by Sam Mousa
Expected 1 space after FOREACH keyword; 0 found
Loading history...
77 11
            if (!preg_match('#(\S+):\s*(.*)#', $line, $matches)) {
78
                throw new Exception("YAML parse error for line: $line");
79
            }
80 11
            $data[$matches[1]] = $matches[2];
81
        }
82 11
        return new ArrayResponse('OK', $data);
83
    }
84
85
    /**
86
     * Callback for array_map to process YAML lines.
87
     *
88
     * @param string $line
89
     *
90
     * @return string
91
     */
92
    private function mapYamlList(string $line):string
93
    {
94
        return ltrim($line, '- ');
95
    }
96
}
97