Passed
Push — develop ( cb60d7...ef7d65 )
by Maarten de
07:14
created

PathParser::parseValuePath()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 6
nc 2
nop 2
dl 0
loc 16
rs 10
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cloudstek\SCIM\FilterParser;
6
7
use Cloudstek\SCIM\FilterParser\Exception\InvalidPatchPathException;
0 ignored issues
show
Bug introduced by
The type Cloudstek\SCIM\FilterPar...validPatchPathException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use Cloudstek\SCIM\FilterParser\Exception\InvalidValuePathException;
9
use Cloudstek\SCIM\FilterParser\Exception\TokenizerException;
10
11
/**
12
 * SCIM Path Parser.
13
 */
14
class PathParser extends AbstractParser implements PathParserInterface
15
{
16
    /**
17
     * SCIM Path Parser.
18
     */
19
    public function __construct()
20
    {
21
        parent::__construct(ParserMode::PATH());
22
    }
23
24
    /**
25
     * Parse path string.
26
     *
27
     * @param string $input Attribute path..
28
     *
29
     * @throws TokenizerException|\Nette\Tokenizer\Exception
30
     *
31
     * @return AST\Path
32
     */
33
    public function parse(string $input): AST\Path
34
    {
35
        $stream = $this->tokenizer->tokenize($input);
36
37
        // Expect attribute or value path.
38
        if ($stream->isNext(self::T_NAME) === false) {
39
            throw new TokenizerException(
40
                sprintf(
41
                    'Expected an attribute or value path, got "%s".',
42
                    $stream->nextValue()
43
                ),
44
                $stream
45
            );
46
        }
47
48
        // Get attribute name
49
        $name = $stream->matchNext(self::T_NAME)->value;
50
51
        // Attribute scheme
52
        $scheme = null;
53
54
        if (strpos($name, ':') !== false) {
55
            $lastColonPos = strrpos($name, ':');
56
            $scheme = substr($name, 0, $lastColonPos);
57
            $name = substr($name, $lastColonPos + 1);
58
        }
59
60
        // Attribute path
61
        $attributePath = new AST\AttributePath($scheme, explode('.', $name));
62
63
        if ($stream->hasNext() === false) {
64
            return $attributePath;
65
        }
66
67
        // Value path
68
        return $this->parseValuePath($stream, $attributePath);
69
    }
70
71
    /**
72
     * @inheritDoc
73
     */
74
    protected function parseInner(Tokenizer\Stream $stream, bool $inValuePath = false): ?AST\Node
75
    {
76
        // @codeCoverageIgnoreStart
77
        if ($inValuePath === false) {
78
            throw new \LogicException('This method should only be called when parsing a value path.');
79
        }
80
        // @codeCoverageIgnoreEnd
81
82
        try {
83
            return parent::parseInner($stream, $inValuePath);
84
        } catch (\Nette\Tokenizer\Exception $ex) {
85
            throw new InvalidValuePathException($stream);
86
        }
87
    }
88
89
    /**
90
     * @inheritDoc
91
     */
92
    protected function parseValuePath(Tokenizer\Stream $stream, AST\AttributePath $attributePath): AST\ValuePath
93
    {
94
        $valuePath = parent::parseValuePath($stream, $attributePath);
95
96
        // Sub attribute
97
        if ($stream->hasNext()) {
98
            $subAttr = $stream->matchNext(self::T_SUBATTR)->value;
99
100
            // Strip off the '.' at the start
101
            $subAttr = ltrim($subAttr, '.');
102
103
            // NOTE: T_SUBATTR matches end of string so no need to check if stream is at the end.
104
            return $valuePath->withSubAttribute($subAttr);
105
        }
106
107
        return $valuePath;
108
    }
109
}
110