Completed
Push — master ( c02018...344583 )
by Bogdan
03:13
created

ExtractorDefinitionBuilder::buildExtractor()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 16
ccs 8
cts 8
cp 1
rs 9.2
c 0
b 0
f 0
cc 4
eloc 8
nc 4
nop 3
crap 4
1
<?php declare(strict_types=1);
2
3
/*
4
 * This file is part of the pinepain/js-sandbox PHP library.
5
 *
6
 * Copyright (c) 2016-2017 Bogdan Padalko <[email protected]>
7
 *
8
 * Licensed under the MIT license: http://opensource.org/licenses/MIT
9
 *
10
 * For the full copyright and license information, please view the
11
 * LICENSE file that was distributed with this source or visit
12
 * http://opensource.org/licenses/MIT
13
 */
14
15
16
namespace Pinepain\JsSandbox\Extractors;
17
18
19
use Pinepain\JsSandbox\Extractors\Definition\ExtractorDefinitionInterface;
20
use Pinepain\JsSandbox\Extractors\Definition\PlainExtractorDefinition;
21
use Pinepain\JsSandbox\Extractors\Definition\PlainExtractorDefinitionInterface;
22
use Pinepain\JsSandbox\Extractors\Definition\VariableExtractorDefinition;
23
24
25
class ExtractorDefinitionBuilder implements ExtractorDefinitionBuilderInterface
26
{
27
    /**
28
     * @var string
29
     */
30
    protected $type_regexp = '/^((?<name>[-_\w]+)(?:\s*\(\s*(?<param>(?-3)*|[\w\\\\]+)\s*\))?(?:\s*\|\s*(?<alt>(?-4)))?)$/';
31
32
    /**
33
     * {@inheritdoc}
34
     */
35 8
    public function build(string $definition): ExtractorDefinitionInterface
36
    {
37 8
        $definition = trim($definition);
38
39 8
        if (!$definition) {
40 1
            throw new ExtractorDefinitionBuilderException('Definition must be non-empty string');
41
        }
42
43 7
        if (preg_match($this->type_regexp, $definition, $matches)) {
44 6
            return $this->buildExtractor($matches['name'], $matches['param'] ?? null, $matches['alt'] ?? null);
45
        }
46
47 1
        throw new ExtractorDefinitionBuilderException("Unable to parse definition: '{$definition}'");
48
    }
49
50
    /**
51
     * @param string      $name
52
     * @param null|string $param
53
     * @param null|string $alt_definitions
54
     *
55
     * @return ExtractorDefinitionInterface
56
     * @throws ExtractorDefinitionBuilderException
57
     */
58 6
    protected function buildExtractor(string $name, ?string $param, ?string $alt_definitions): ExtractorDefinitionInterface
59
    {
60 6
        $next = null;
61
62 6
        if ($param && preg_match($this->type_regexp, $param, $matches)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $param of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
63 3
            $next = $this->buildExtractor($matches['name'], $matches['param'] ?? null, $matches['alt'] ?? null);
64
        }
65
66 6
        $definition = new PlainExtractorDefinition($name, $next);
67
68 6
        if ($alt_definitions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $alt_definitions of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
69 2
            $definition = $this->buildVariableDefinition($definition, $alt_definitions);
70
        }
71
72 6
        return $definition;
73
    }
74
75
    /**
76
     * @param PlainExtractorDefinitionInterface $definition
77
     * @param string                            $alt_definitions
78
     *
79
     * @return VariableExtractorDefinition
80
     * @throws ExtractorDefinitionBuilderException
81
     */
82 2
    protected function buildVariableDefinition(PlainExtractorDefinitionInterface $definition, string $alt_definitions): VariableExtractorDefinition
83
    {
84 2
        $alt = [$definition];
85
86 2
        while ($alt_definitions && preg_match($this->type_regexp, $alt_definitions, $matches)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $alt_definitions of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
87
            // build alt
88 2
            $alt[] = $this->buildExtractor($matches['name'], $matches['param'] ?? null, null);
89
90 2
            $alt_definitions = $matches['alt'] ?? null;
91
        }
92
93 2
        if ($alt_definitions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $alt_definitions of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
94
            // this should not be possible, but just in case we will ever get here
95
            throw new ExtractorDefinitionBuilderException('Invalid varying definition');
96
        }
97
98 2
        return new VariableExtractorDefinition(...$alt);
99
    }
100
101
}
102